算法筆記

一、逆序想到 stack ; 好比 445. 兩數相加 II,固然,能夠用 stack 也是能夠用 List,list 有序,所以也是能夠看成 stack 用;html

二、要求達到 O(n \log n)O(nlogn) 的時間複雜度和 O(1)O(1) 的空間複雜度,時間複雜度是 O(n \log n)O(nlogn) 的排序算法包括歸併排序、堆排序和快速排序(快速排序的最差時間複雜度是 O(n^2)O(n2)),其中最適合鏈表的排序算法是歸併排序。算法

三、對於鏈表,有時候須要把頭結點加入循環,能夠在頭結點前面在家一個節點,這樣就能夠用於判斷了;數組

四、鏈表經常使用的操做邏輯,用 stack, 數組保存節點組成新的隊列;用一個新節點來鏈接原來的節點,這樣,即便對原有節點改變了,仍是能夠返回頭結點。熟悉鏈表的反轉,合併等邏輯。ide

五、關於二叉樹,二叉樹通常採用遞歸,通常是遞歸到最後一個的時候,在不斷往前,所以你要作好最好一個判斷究竟是返回什麼,好比深度的求解等等。spa

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        } else {
            int leftHeight = maxDepth(root.left);
            int rightHeight = maxDepth(root.right);
            return Math.max(leftHeight, rightHeight) + 1;  // 這裏加1,不斷遞歸,數值就變大了
        }
    }
}

 六、二叉樹的遞歸調用其實就是存在一個隱藏的stack。只是你們平時熟悉了遞歸,沒有去細想內部的邏輯。因此若是不採用遞歸方式來實現,就是得采用 stack 來維護這個順序,可是要注意先入後出這個點。指針

七、若是給你一個數組 num1 足夠空間,前部分已經存在值了,讓你把另外一個 num2 的值填到 num1 中。這種要麼新建一個數組,填完後再挪到 num1 中,另外一種是從合併後的長度開始填,這樣確保不會覆蓋 num1 前面已有的值。可參考 88. 合併兩個有序數組code

八、兩個字符串找不一樣,對於字符串能夠採用求和,位運算,以及一個數組來記錄各個字母出現的個數,以此來找到不一樣。參考:389. 找不一樣htm

 1 // 求和
 2 class Solution {
 3     public char findTheDifference(String s, String t) {
 4         int as = 0, at = 0;
 5         for (int i = 0; i < s.length(); ++i) {
 6             as += s.charAt(i);
 7         }
 8         for (int i = 0; i < t.length(); ++i) {
 9             at += t.charAt(i);
10         }
11         return (char) (at - as);
12     }
13 }
14 
15 // 計數
16 class Solution {
17     public char findTheDifference(String s, String t) {
18         int[] cnt = new int[26];
19         for (int i = 0; i < s.length(); ++i) {
20             char ch = s.charAt(i);
21             cnt[ch - 'a']++;
22         }
23         for (int i = 0; i < t.length(); ++i) {
24             char ch = t.charAt(i);
25             cnt[ch - 'a']--;
26             if (cnt[ch - 'a'] < 0) {
27                 return ch;
28             }
29         }
30         return ' ';
31     }
32 }
33 
34 // 位運算
35 class Solution {
36     public char findTheDifference(String s, String t) {
37         int ret = 0;
38         for (int i = 0; i < s.length(); ++i) {
39             ret ^= s.charAt(i);
40         }
41         for (int i = 0; i < t.length(); ++i) {
42             ret ^= t.charAt(i);
43         }
44         return (char) ret;
45     }
46 }
兩個字符串找不一樣

九、翻轉二叉樹,這道題目遇到過好幾遍,雖然知道翻轉,可是就不知道如何寫比較好:226. 翻轉二叉樹blog

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (root == null) {
            return null;
        }
        // 若是此時左右節點已經爲 null 了,那麼就會執行後面的交換邏輯,而後遞歸就會回到父節點那一層
        TreeNode left = invertTree(root.left);
        TreeNode right = invertTree(root.right);
        root.left = right;
        root.right = left;
        return root;
    }
}
    

 十、關於遞歸。我感受本身對遞歸仍是沒有理解透徹。排序

對於509. 斐波那契數,我能夠很輕鬆寫下 以下代碼,並不會以爲有啥問題。

class Solution {
    public int fib(int n) {
        if (n==1 || n==2) return 1;
        return fib(n-1)+ fib(n-2);
    }
}

一樣的,對於129. 求根節點到葉節點數字之和,也是遞歸,可是對於二叉樹的遞歸我確實很忐忑,老是以爲本身寫的代碼會有啥問題,具體代碼以下:

class Solution {
    public int sumNumbers(TreeNode root) {
        return dfs(root, 0);
    }

    public int dfs(TreeNode root, int prevSum) {
        if (root == null) {
            return 0;
        }
        int sum = prevSum * 10 + root.val;
        if (root.left == null && root.right == null) {
            return sum;
        } else {
            // 既然你知道是遞歸,同時你也把遞歸的分支搞清楚了,只有左右兩個分支,所以你就寫下就是了
            return dfs(root.left, sum) + dfs(root.right, sum);
        }
    }
}
    

 還有就是我在想,是否是應該按照第一題同樣,先把遞歸的狀態搞清楚,也就是當前狀態和前面幾個狀態是啥關係,有幾個分支。都理清楚了可能就好寫了。而後把遞歸的結束條件分析清楚就好,結束條件放在前面,遞歸邏輯放在後面,只有沒有結束纔是能夠進入遞歸的。

十、對於二分法要時刻關注只有兩個元素的狀況,好比:[1,2],[2,1]。這時候 middle = left。這時候注意 left 和 right 之間的關係。

十一、在作加法和乘法的點時候要考慮會不會存在溢出的狀況,一旦溢出,結果就不同了。能夠考慮乘法變成除法,加法變成減法,以此逃過溢出。

 

附算法系列文章

滑動窗口算法基本原理與實踐

廣度優先搜索原理與實踐

深度優先搜索原理與實踐

雙指針算法基本原理和實踐

分治算法基本原理和實踐

動態規劃算法原理與實踐

算法筆記

相關文章
相關標籤/搜索