算法解题模版
本文最后更新于:2021年9月17日 下午
链表遍历框架,兼具迭代和递归结构 class ListNode { int val; ListNode next; }void traverse (ListNode head) { for (ListNode p = head; p != null; p = p.next) { } }void traverse (ListNode head) { traverse(head.next) }
二叉树遍历框架
class TreeNode { int val; TreeNode left, right; }void traverse (TreeNode root) { traverse(root.left); traverse(root.right); }
class TreeNode { int val; TreeNode[] children; }void traverse (TreeNode root) { for (TreeNode child : root.children) traverse(child); }
二分搜索树遍历框架 void BST (TreeNode root, int target) { if (root.val == target) if (root.val < target) BST(root.right, target); if (root.val > target) BST(root.left, target); }
深度优先搜索 DFS 模版 借助栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int xx[4 ] = {-1 , 1 , 0 , 0 }, yy[4 ] = {0 , 0 , -1 , 1 };int vis[][] = {0 }; int res = 0 ; int ex, ey; void dfs (int x, int y) { if (x == ex && y == ey) { res++; return ; } vis[x][y] = 1 ; for (int i = 0 ; i < 4 ; ++i) { int nx = x + xx[i]; int ny = y + yy[i]; if (!vis[nx][ny] || (nx, ny)不能越界 ) { dfs(nx, ny); } } vis[x][y] = 0 ; }
广度优先搜索 BFS 模版 借助队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 int xx[4 ] = {-1 , 1 , 0 , 0 }, yy[4 ] = {0 , 0 , -1 , 1 };int vis[][] = {0 }; int res = 0 ; struct node { int x, y; node(int x, int y) : x(x), y(y) {} };void bfs (int sx, int sy) { queue <node> q; q.push(node(sx, sy)); vis[sx][sy] = 1 ; while (!q.empty()) { node tmp = q.front(); q.pop(); for (int i = 0 ; i < 4 ; ++i) { int nx = tmp.x + xx[i]; int ny = tmp.y + yy[i]; if ( (nx, ny)合法可以进行搜索 ) { 走到(nx, ny)的步数 = 走到(tmp.x, tmp.y) + 1 ; q.push(node(nx, ny)); vis[nx][ny] = 1 ; } } } }
拓扑排序 参考:检测循环依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 vector <int > haveCircularDependency (int n, vector <vector <int >> &prerequisites) { vector <vector <int >> g(n); vector <int > indeg (n) ; vector <int > res; for (int i = 0 ; i < prerequisites.size(); i ++) { int a = prerequisites[i][0 ], b = prerequisites[i][1 ]; g[a].push_back(b); indeg[b] ++; } queue <int > q; for (int i = 0 ; i < n; i ++) { if (indeg[i] == 0 ) q.push(i); } while (q.size()) { int t = q.front(); q.pop(); res.push_back(t); for (int i = 0 ; i < g[t].size(); i ++) { int j = g[t][i]; indeg[j] --; if (indeg[j] == 0 ) { q.push(j); } } } if (res.size() == n) return res; else return {}; }
滑动窗口算法框架 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 void slidingWindow (string s, string t) { unordered_map <char , int > need, window; for (char c : t) need[c]++; int left = 0 , right = 0 ; int valid = 0 ; while (right < s.size()) { char c = s[right]; right++; ... printf ("window: [%d, %d)\n" , left, right); while (window needs shrink) { char d = s[left]; left++; ... } } }
递归三部曲
明确递归函数的参数和返回值
明确终止条件
明确单层递归的逻辑
回溯三部曲
回溯函数模板返回值以及参数
回溯函数终止条件
回溯搜索的遍历过程
result = [] def backtrack(路径, 选择列表): if 满足结束条件: result.add(路径) return for 选择 in 选择列表: 做选择 backtrack(路径, 选择列表) 撤销选择
动规五部曲
确定dp数组(dp table)以及下标的含义
确定递推公式
dp 数组初始化
确定遍历顺序
举例推导 dp 数组