java算法易筋經:常見java-API使用技巧

摘要:算法練習的本質也在於鍛鍊編程思惟,強化程序員的內力。所以給本身後面會持續更新的算法技巧內容簡稱算法易筋經。

本文分享自華爲雲社區《<java算法易筋經>之常見java-API使用》,原文做者:breakDraw 。java

易筋經源於我國古代中醫導引術,具備強健體魄、預防疾病的效果,長期以來在佛家及民間習武人士之間廣爲流傳。算法練習的本質也在於鍛鍊編程思惟,強化程序員的內力。所以給本身後面會持續更新的算法技巧內容簡稱算法易筋經。程序員

不管你使用什麼語言開始訓練算法, 老是得掌握基本的。 我這邊只以java舉例,其餘語言相似。以leetcode類型的平臺爲主。算法

java數組和list互轉

有時候給定的輸入是個數組,中間過程咱們想轉成list並使用list的一些api。 可是這沒那麼簡單。編程

請打開本身的編譯器,而後看下下面幾個問題可否不用for循環寫成功。(用for循環也是對的,考試時若是忘記了,就選擇能用的方法)api

  • 請把字符串數組轉list
  • 請把字符串list轉數組
  • 請把list<Integer>轉int[]
  • 請把int[]轉成List<Integer>

就像下面這樣,本身造個類,測試一下看可否秒寫:數組

public class ListArrayUtil {
    // 請把字符串數組轉list
    public List<String> arrToListStr(String[] arr) {
        return null;
    }

    // 請把字符串list轉數組
    public String[] listToArrStr(List<String> list) {
        return null;
    }

    // 請把list數組轉成int[]
    public List<Integer> arrToListInt (List<Integer> num) {
        return null;
    }

    // 請把int[] 數組轉成list
    public List<Integer> arrToListInt (int[] num) {
        return null;
    }
}

有些人可能會誤覺得int[]和Integer[]是能夠自動轉的,而後對於數組而言,編譯器沒法用識別,會報錯。所以若是涉及這種基礎類型的數組列表轉換,請記住要麼立刻使用stream,要麼直接for循環寫一下,不要卡在這個編譯錯誤這研究半天。ide

個人答案:測試

public class ListArrayUtil {
    // 請把字符串數組轉list
    public List<String> arrToListStr(String[] arr) {
        return Arrays.asList(arr);
    }

    // 請把字符串list轉數組
    public String[] listToArrStr(List<String> list) {
        return list.toArray(new String[list.size()]);
    }

    // 請把list數組轉成int[]
    public int[] arrToListInt (List<Integer> list) {
        // 不能夠toArray,int[]和Integer[]是不一樣的
        //return list.toArray(new int[list.size()]);
        return list.stream()
                .mapToInt(Integer::valueOf)
                .toArray();
    }

    // 請把int[] 數組轉成list
    public List<Integer> arrToListInt (int[] num) {
        // 不能夠asList,由於int[]和Integer[]不一樣
        // return Arrays.<Integer>asList(num);
        return Arrays
                .stream(num)
                .boxed()
                .collect(Collectors.toList());
    }
}

list和數組的初始化

初始化可沒那麼簡單,尤爲是涉及返回List[]做爲結果時,老是有人會忘記要先初始化數組裏的每一個list才能使用。請完成如下內容:優化

  • 初始化list<Integer>爲5個1
  • 初始化int[]爲5個1
  • 初始化1個包含5個list的lis[]數組,而且裏面的list已經初始化完成

正確答案以下:ui

public class ListUtil {

    // 初始化list爲5個1
    public static List<Integer> fillList() {
        List<Integer> list = Collections.nCopies(5,1);
        System.out.println(list);
        return list;
    }

    // 初始化arr爲5個1
    public static int[] fillArr() {
        int[] arr = new int[5];
        Arrays.fill(arr, 1);
        return arr;
    }

    // 返回1個list數組,而且裏面的list已經初始化完成
    public static List[] fillListArray() {
        List[] lists = new List[5];
        IntStream.rangeClosed(0, 4).boxed()
                .forEach(i->lists[i] = new ArrayList());
        return lists;
    }
}

排序

關於如何快速對list和數組排序,在IDEA本身解答如下問題:

  • Arrays和List如何對int[]數組作倒序排序
    Arrays.sort()
    Collections.sort()
  • 對於一個新對象,怎麼作自定義排序?
    以下。定義一個comparable
public class Student implements Comparable<Student> {
    private  int stuId;
    private String stuName;
    private int score;
    @Override
    public int compareTo(Student o) {
        return stuId-o.stuId;
    }
}

參考題目: https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/

map相關

  • 若是map裏的value是個list,每次往某個key裏的list放數據時,必需要先初始化list, 怎麼減小初始化代碼?

答案:
使用getOrDefault:
map.getOrDefault(key, new ArrayList<>()).add(xxx)
圖結果那邊還蠻經常使用的

不作重複的put

if (!map.containsKey(key)) {    
    map.put(key, value);
}

能夠優化成
map.putIfAbsent(key, value)
字面意思: absent指不存在,那麼就是不存在的時候,把value放入,若是存在,則直接返回原value值。

map中的值作更新

例如每次對key中的值加1
有兩種方式:

map.put(key, map.getOrDefault(key, 0)+1);
map.compute(key, (k,v)->(v==null?1:v+1));

在一個比較複雜的狀況下,compute比較有用。

computeIfAbsent(key, (k,v)->f(k,v)) 只在key不存在的時候,才計算這個labmda式子。 若是存在的話,就不計算了,直接返回舊值。

computeIfPresent(key, (k,v)->f(k,v)) 只有存在纔會更新,不存在就不更新。

常見隊列用法

  • 普通隊列:
  • 優先隊列priorityQueue:
    可以保證出隊的永遠是按照你設定的最大或者最小的元素。
    頗有用。

用labma寫內部比較式子,避免忘記接口怎麼寫
PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> a[1] - b[1]);
a[1] - b[1] 是小頂堆
a[1]-b[1] >0,則交換。

如何記憶?
堆更新的時候,都是從上往下更新的, 讓
那麼a是上面的點,b是下面的點(兒子節點)
當返回大於0時,交換a和b。

這樣就好理解了
大頂堆: a-b<0時,須要交換,即父親比兒子小,因此須要交換
小丁堆: a-b>0, 須要交換, 即父親比兒子大,得換,讓父親是小頂。

  • 優先隊列延時刪除
    當優先隊列中某個元素會被刪除,可是不在堆頂時,使用延遲刪除, 直到他走到堆頂纔會清理。
    所以這時候要使用額外的數量realCount來統計隊列實際數量, 並使用特定的刪除標誌位(勿用會干擾到隊列compare方法的方式去設定刪除標誌位)

簡易二分查找

  • 在一個list中找到最靠近x且大於等於x值的元素

不想手寫二分的話用這個方法:

  • 在一個list中找到最靠近x且小於等於x的元素
    使用treeMap放置數據
    floorKey(key) 能夠找到小於等於給定鍵的最大鍵
    若是不存在這樣的鍵,則返回null。

ceilingKey(key) 找到大於等於給定鍵的最小鍵
不存在則返回null

記憶:

ceiling向上舍入,那就是找key的上邊。 ceiling有天花板的意思,因而就理解成是向上找。

floor 向下攝入,那就是找key的下邊。 有沉入水下的意思,因而理解成向下。

  • 在list中找到最靠近x且大於(不包含等於)x的元素

例題: https://leetcode-cn.com/problems/previous-permutation-with-one-swap/submissions/

 

點擊關注,第一時間瞭解華爲雲新鮮技術~

相關文章
相關標籤/搜索