算法笔记

一、逆序想到 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 之间的关系。

十一、在作加法和乘法的点时候要考虑会不会存在溢出的状况,一旦溢出,结果就不同了。能够考虑乘法变成除法,加法变成减法,以此逃过溢出。

 

附算法系列文章

滑动窗口算法基本原理与实践

广度优先搜索原理与实践

深度优先搜索原理与实践

双指针算法基本原理和实践

分治算法基本原理和实践

动态规划算法原理与实践

算法笔记

相关文章
相关标签/搜索