Some basic ideas of classic problems/algorithms.
BinarySearch
- https://leetcode.com/problems/maximum-value-at-a-given-index-in-a-bounded-array/
- https://leetcode.com/problems/arranging-coins/
2020更新:根据这个算法总结了一个不那么绕的二分查找
Deprecated
Sort
Selection Sort
外层循环i从头到尾、内层循环从i往后,每次找最小值所在的index,内层循环结束后和头部swap,这样每次都可以把当前最小值放到最前面。
Insertion Sort
外层循环i从前往后遍历,内层循环从i往前,每次将相邻的顺序反了的元素swap。
Shell Sort
插入排序的升级版,循环的interval是从大到小的。排序的本质是消除逆序对,如果增大interval,则一次swap可能会消除更多的逆序对,因此可以突破O(N^2).
Bubble Sort
外层循环从头到尾,内层循环从尾到i + 1不断把较小值放到前面。
Bucket Sort
木桶排序牺牲了空间换取速度,达到了O(N)。统计每个值出现的个数,然后依次放回原数组。
Radix Sort[====TODO====]
基数排序就是根据每个位数字大小,从个位数、十位数、百位数、千位数…存入bucket
Merge Sort
分治法思想,将两个序列不断拆分,拆到不能再拆后分别排序后合并。归并排序(以及插入排序)是稳定的。
Quick Sort + Shuffle
定义一个pivot值,找到它的位置使得左边都小于等于它、右边都大于等于它,然后再递归到两边去排。最差情况出现在当已经有序的时候,退化成O(N^2),因为每个pivot都要和后面的比较一波。
Big Integer Calculation
|
|
GCD
|
|
Union Find
并查集:在UF类中维护一个id数组,这个id表示当前索引的祖宗的索引,若id[idx] = idx
说明它本身就是老大,初始时每个元素都是自己的老大。find(p)
函数就是返回p的老大的索引,union(p, q)
函数就是将索引p和q两伙合并起来,分别找到p和q的老大索引pRoot和qRoot,但是他们谁隶属于谁呢?rank就是在这时候起作用,将rank高的保留,rank低的老大合并到更高的老大那去,若两个老大一样,就随意了,合并后新老大的rank要加加。在UF中还有一个count变量,其实就是算有几个独立老大的,初始时每个1都是老大,而每次成功调用union时count都会减减。
https://leetcode.com/problems/number-of-islands/
Backtracking
Subset(无重复元素)
|
|
Subset(有重复元素)
|
|
Permutations(无重复元素全排列)
|
|
Permutations(有重复元素全排列)
|
|
Combinations
|
|
combination-sum(无重复元素可重复组合求和)
|
|
combination-sum(有重复元素不可复用组合求和)
|
|
KMP算法
根据pattern构建有限状态机的DP数组,然后再取给定的一堆text中找匹配的索引。
dp[j][c] = next
表示,当前是状态j
,遇到了字符c
,应该转移到状态next
. 需要一个辅助状态X
,它永远比当前状态j
落后一个状态,拥有和j
最长的相同前缀,我们给它起了个名字叫「影子状态」.1234567891011121314151617181920212223242526272829303132333435363738public class KMP {private int[][] dp;private String pattern;public KMP(String pattern) {this.pattern = pattern;int M = this.pattern.length()// dp[状态][字符]表示需要转移到的下一个状态dp = new int[][256];// 最开始只有和第一个字符匹配才能让pattern转移到下一个状态dp[0][this.pattern.charAt(0)] = 1;// 影子状态,表示相同前缀的部分,当后续状态不匹配需要回滚时就需要参考影子状态的nextint X = 0;for (int j = 1; j < M; j++) {for (int c = 0; c < 256; c++) {dp[j][c] = dp[X][c]; // j状态的前缀和X状态的前缀是一样的,因此状态转换可以通用}dp[j][pattern.charAt(j)] = j + 1; // 匹配了就转移到pattern的下一位X = dp[X][pattern.charAt(j)]; // 遇到了j处字符,则让影子状态转移到对应字符的状态}}public int search(String text) {int M = pattern.length();int N = text.length();int j = 0;for (int i = 0; i < N; i++) {// 从0状态出发,根据出现的字符找下一个状态j = dp[j][text.charAt(i)];if (j == M) {// pattern在text中的起始索引return i - M + 1;}}return -1;}}此外再介绍leetcode模版。在构建pattern的dp数组时索引从1开始且单向前进,在text中搜索时索引从0开始且时单向前进。
12345678910111213141516171819202122232425262728293031323334class Solution {public int strStr(String haystack, String needle) {if (haystack == null || needle == null || needle.isEmpty()) {return 0;}int len = needle.length();int[] dp = new int[len]; // 构建needle的failure function数组for (int i = 1; i < len; i++) {int j = dp[i - 1]; // 当前最长common后缀前缀的长度while (j > 0 && needle.charAt(j) != needle.charAt(i)) {j = dp[j - 1]; // 失配则转移到上一个状态,即以char[dp[i - 1] - 1]结尾的状态}if (needle.charAt(j) == needle.charAt(i)) {j++;}dp[i] = j;}int lenFull = haystack.length();int j = 0;for (int i = 0; i < lenFull; i++) {while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {j = dp[j - 1];}if (haystack.charAt(i) == needle.charAt(j)) {j++;}if (j == len) {return i - len + 1;}}return -1;}}- https://leetcode.com/problems/rotate-string/
- https://leetcode.com/problems/repeated-substring-pattern/
- https://leetcode.com/problems/longest-happy-prefix/
- https://leetcode.com/problems/shortest-palindrome/
- https://leetcode.com/problems/encode-string-with-shortest-length/
Stack
Tree
https://leetcode.com/problems/boundary-of-binary-tree/
Preorder Iterative
|
|
Inorder Iterative
|
|
Count Nodes in Complete BT
- complete二叉树是指每一层都逐步从左到右填充节点,左右孩子高度差顶多为1. 计算有多少个节点在普通二叉树中是
O(N)
,而在完美二叉树中节点数就是高度的二次幂,因此O(logN)
求高度即可。而在完全二叉树中直接遍历比较蠢,就得想怎么利用高度做文章。如果左右孩子的高度一样,那就直接照搬完美二叉树;如果不同就继续按照O(N)
递归。时间复杂度为O(logN * logN)
(每次递归的复杂度为logN,总共只需要logN次递归,因为完全二叉树其中一个子树一定为完美二叉树,并不是每一次都会触发递归)12345678910111213141516public int countCompleteTreeNodes(TreeNode root) {TreeNode l = root, r = root;int heightLeft = 0, heightRight = 0;while (l != null) {l = l.left;heightLeft++;}while (r != null) {r = r.right;heightRight++;}if (heightLeft == heightRight) {return (int)Math.pow(2, heightLeft) - 1;}return 1 + countCompleteTreeNodes(root.left) + countCompleteTreeNodes(root.right);}
Postorder Iterative
|
|
Trie
- https://leetcode.com/problems/longest-common-prefix/
- https://leetcode.com/problems/design-search-autocomplete-system/
String
substring palindrome: 516, 647.
https://leetcode.com/submissions/detail/121291766/
https://leetcode.com/submissions/detail/121292245/
- DP State transition:
dp[i][j]
means taking char from i to j of original string, and check next char if it equals to the leading char of current row. If so, take the previous resultdp[i + 1][j - 1]
to update. - Cached DFS: https://discuss.leetcode.com/topic/78603/straight-forward-java-dp-solution