思维
二维数组旋转
https://labuladong.gitee.io/algo/di-yi-zhan-da78c/shou-ba-sh-48c1d/er-wei-shu-150fb/
- 顺时针旋转:
\
对角线翻转,再水平翻转
- 逆时针旋转:
/
对角线翻转,再水平翻转。
二叉树
动归/DFS/回溯算法都可以看做二叉树问题的扩展,只是它们的关注点不同:
- 动态规划算法属于分解问题的思路,它的关注点在整棵「子树」。
- 回溯算法属于遍历的思路,它的关注点在节点间的「树枝」。
- DFS 算法属于遍历的思路,它的关注点在单个「节点」。
Code
回溯算法
组合子集用start
,额外传参i+1
排列用used
,不用额外传参
- 形式一、元素无重不可复选,即
nums
中的元素都是唯一的,每个元素最多只能被使用一次,backtrack
核心代码如下:
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
| void backtrack(vector<int>& nums, int start) { for (int i = start; i < nums.size(); i++) { track.push_back(nums[i]); backtrack(nums, i + 1); track.pop_back(); } }
void backtrack(vector<int>& nums) { for (int i = 0; i < nums.size(); i++) { if (used[i]) { continue; } used[i] = true; track.push_back(nums[i]); backtrack(nums); track.pop_back(); used[i] = false; } }
|
- 元素可重不可复选,即
nums
中的元素可以存在重复,每个元素最多只能被使用一次,其关键在于排序和剪枝,backtrack
核心代码如下:
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 31 32 33 34 35 36 37 38 39 40 41 42
| sort(nums.begin(), nums.end());
void backtrack(vector<int>& nums, int start) { for (int i = start; i < nums.size(); i++) { if (i > start && nums[i] == nums[i - 1]) { continue; } track.push_back(nums[i]); backtrack(nums, i + 1); track.pop_back(); } }
sort(nums.begin(), nums.end());
void backtrack(vector<int>& nums, vector<bool>& used) { for (int i = 0; i < nums.size(); i++) { if (used[i]) { continue; } if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) { continue; } used[i] = true; track.push_back(nums[i]);
backtrack(nums, used); track.pop_back(); used[i] = false; } }
|
- 元素无重可复选,即
nums
中的元素都是唯一的,每个元素可以被使用若干次,只要删掉去重逻辑即可,backtrack
核心代码如下:
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 31 32 33
| void backtrack(vector<int>& nums, int start, vector<int>& track) { for (int i = start; i < nums.size(); i++) { track.push_back(nums[i]); backtrack(nums, i+1, track); track.pop_back(); } }
void backtrack(vector<int>& nums, vector<int>& track) { if (track.size() == nums.size()) { return; } for (int i = 0; i < nums.size(); i++) { if (find(track.begin(), track.end(), nums[i]) != track.end()) { continue; } track.push_back(nums[i]); backtrack(nums, track); track.pop_back(); } }
|
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 30
| int BFS(Node start, Node target) { queue<Node> q; unordered_set<Node> visited; q.push(start); visited.insert(start); int step = 0;
while (!q.empty()) { int sz = q.size(); for (int i = 0; i < sz; i++) { Node cur = q.front(); q.pop(); if (cur == target) return step; for (Node x : cur.adj()) { if (visited.count(x) == 0) { q.push(x); visited.insert(x); } } } step++; } }
|
二分法模板
前面代码完全一致,只有后面三行代码不同。
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| int binary_search(vector<int>& nums, int target) { int left = 0, right = nums.size() - 1; while(left <= right) { int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; } else if (nums[mid] > target) { right = mid - 1; } else if(nums[mid] == target) { return mid; } } return -1; }
int left_bound(vector<int>& nums, int target) { int left = 0, right = nums.size() - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; } else if (nums[mid] > target) { right = mid - 1; } else if (nums[mid] == target) { right = mid - 1; } } if (left == nums.size()) return -1; return nums[left] == target ? left : -1; }
int right_bound(vector<int>& nums, int target) { int left = 0, right = nums.size() - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; } else if (nums[mid] > target) { right = mid - 1; } else if (nums[mid] == target) { left = mid + 1; } } if (right ==-1) return -1; return nums[right] == target ? right : -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 31 32
| bool checkInclusion(string s1, string s2) { unordered_map<char, int> need,window; for(char ch : s1) need[ch]++; int left=0,right=0; int valid=0; vector<int> rt;
while(right<s2.size()){ char cur=s2[right]; right++; if(need.count(cur)){ window[cur]++; if(window[cur]==need[cur]) valid++; }
while(right-left>=s1.size()){ if(valid==need.size()){ return true; }
char d=s2[left]; left++; if(need.count(d)){ if(window[d]==need[d]) valid--; window[d]--; } } } return false;
|