链表反转
ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode cnext = curr.next;
if (prev == null) {
curr.next = null;
} else {
curr.next = prev;
}
prev = curr;
curr = cnext;
}
return prev;
}
分治算法
- pow算法递归:需要额外的栈空间
-
n=0 return 1; n<0 return 倒数; n%2==0 y * y; y = pow(x, n/2); return N % 2 == 0 ? y * y : y * y * x;
- pow算法迭代:
-
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200509225535846.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21peWFfc3VuamNfY3Nkbg==,size_16,color_FFFFFF,t_70)
只能买卖一次的股票问题
// dp[i][0] 永远等于 0
// dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])
// dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i])
或者是 dp[i][0] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);dp[i][1] = max(dp[i - 1][1], -prices[i])
0-1 背包问题
- dp[i][j] = max(dp[i-1][j], dp[i-1][W-wt[i-1]] + val[i-1]; 一维:dp[j]=max(dp[j],dp[W-wt[i-1]+val[i-1]]) 0-1背包问题。
- f[j] = maxj{f[j], f[j−a[i]]+b[i]} 完全背包问题,无限使用。
- f[j] = max{f[j], f[j−k∗a[i]]+k∗b[i]} 多重背包问题,个数限定。
广度优先搜索 BSF
- queue 如果是图的话需要visited列表记录遍历过的节点 人类熟悉
- 深度优先DSF 机器熟悉 stack 推荐递归
- Batch process
- 剪枝
二分查找模板
left, right = 0, len - 1
while(left<=right){
mid = left + right /2
if(mid == target) return mid
if(mid > target) right = mid - 1
if(mid<target) left = mid + 1
sqrt 思路二分法:[0, target] mid = 0 + target /2 y = mid*mid > target r = mid else l = mid
牛顿迭代法 Xn-1 = Xn - f(Xn)/f`(Xn) = Xn - Xn2 - Y0/2Xn = Xn + Y0/Xn / 2
字典树 trie
使用hash或者数组存会有很多重复单词或字符
trie用边存字符字母,所走的路径就是单词,用100多条边和20多层深度的trie就可以存全量的单词
查询速度快比哈希表还快,叶子节点代表单词
TrieNode class{
children = new TrieNode[alphabet_size] 儿子节点
boolean isEndOfWord = true; 是否是叶子节点
}
位运算
& 都为1 为1
| 都为0 为0
异或 相同为0, 不同为1
X & 1 == 1 判断奇偶性
X = X&(X-1) = 清零最低位1
X & -X 得到最低位的1
统计1的个数思路:1. 取余 n++ X >>1 循环 2. x = x & (x-1)
231 power of two 思路: 2的n次方二进制位只有一个1 n = 0 && !(n&n-1)
338 counting bits思路:从1开始循环 bit[i] = bit[i&(i-1)] + 1 i&(i-1)=前结点的下标
52 N皇后问题思路:
class Solution {
int count = 0;
public int totalNQueens(int n) {
if(n < 1) return 0;
dfs(0,0,0,0,n);
return count;
}
public void dfs(int row, int col, int pie, int na, int n){
// 递归终止条件
if(row == n) {
count++;
return;
}
// 位运算得到有效的空位
int bit = ~(col|pie|na)&((1<<n)-1);
// while循环回溯调用
while(bit > 0){
// 做选择 获取空位
int p = bit & -bit;
// 递归
dfs(row+1,col|p,(pie|p)<<1,(na|p)>>1,n);
// 撤销选择 打掉最后一个空位
bit = bit&(bit-1);
}
}
}
动态规划 Dynamic Programming
- 递归+记忆化 -> 递推
- 状态的定义: dp[n] opt[n] fib[n]
- 状态转移方程: dp[n] = best_of(dp[n-1], dp[n-2], …)
- 最优子结构 - 所有的子问题都是最优的
- 自底向上递推 小人走二维数组 dp[i, j] = dp[i - 1, j] + dp[i, j - 1];
- 回溯 递归 - 重复计算 memo
- 贪心 - 永远局部最优
- DP - 记录局部最优子结构、多种记录值
- 70 爬楼梯 climbing stairs elevator escalector 思路: f(n) = f(n-1) + f(f-2) 倒数1阶和2阶都可以直接上去
- 120 Triangle 三角形路径最小和 状态定义 dp[i][j] 指从bottom - up 所有节点和的最小值 path sum min
- dp[i][j] = min(dp[i+1][j], dp[i+1][j+1]) + nums[i][j] 状态压缩 dp[j] = min(dp[j] , dp[j+1]) + nums[i][j]
- 152 max product subarray
股票系列DP
- 121 122 123 309 188 714
- 121 只能买一次 122 无数次 123 2次 309 cool down隔天买 188 k次
- dp[i] 第i天最大利润max profit
- dp[i][2] = dp[i-1][0] - nums[i]
编辑距离 dp[i][j] i = word1的前i个字符,j=word2的前j个字符, 最小编辑距离。 结果dp[m][n] 。
if(word1[i] == word2[j]) dp[i][j] = dp[i-1][j-1] else min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])
class Solution { public int minDistance(String word1, String word2) { int m = word1.length(), n = word2.length(); // 有一个字符串为空串 if (n * m == 0) return n + m; int dp[][] = new int[m+1][n+1]; for(int i = 0; i < m+1; i++){dp[i][0] = i;} for(int j = 0; j < n+1; j++){dp[0][j] = j;} for(int i = 1; i < m+1; i++){for(int j = 1; j < n+1; j++){ if(word1.charAt(i - 1) == word2.charAt(j - 1)) dp[i][j] = dp[i-1][j-1]; else dp[i][j] = Math.min(Math.min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1]) + 1; }} return dp[m][n]; } }
UF union find200 岛屿个数 1、染色floodfill 遍历 == 1 附近节点变为0递归,count++。