四、搜索与回溯算法
-
DFS,本质是递归
- 递推参数
- 终止条件
- 递推工作
- 回溯
-
BFS,本质是队列
queue<int> que; que.push(第一个参数); while(!que.empty()) { auto tmp = que.front(); que.pop(); if(终止条件) continue; //进行递推工作 que.push(新的参数); }
-
树的递归调用
- 某函数既然可以递归调用root,那么也一定可以调用root->left和root->right,有时候只需要把任务分解成三部分即可,root节点,递归调用root->left,递归调用root->right
- 树的遍历方式总体分为两类,DFS和BFS
- DFS,前序,中序,后序,其中中序是递增序列
- BFS,层序
-
剑指12,矩阵中的路径
//时间O(mn3^k),空间O(k) //标准dfs+剪枝,值得学习 class Solution { public: bool exist(vector<vector<char>>& board, string word) { //每个位置都要作为起点尝试一次 for(int i=0;i<board.size();++i) { for(int j=0;j<board[0].size();++j) { if(dfs(i,j,0,board,word)) return true; } } return false; } private: bool dfs(int i,int j,int k,vector<vector<char>>& board, string &word) { //如果越界或者字符不匹配 if(i < 0 || i >= board.size() || j < 0 || j >= board[0].size() || board[i][j] != word[k]) return false; //执行到这步默认字符匹配,且是最后一个字符 if(k == word.size()-1) return true; //递推工作,修改值 board[i][j] = '\0'; //如果有一条路径成功就返回 auto res = dfs(i,j+1,k+1,board,word) || dfs(i,j-1,k+1,board,word) || dfs(i+1,j,k+1,board,word) || dfs(i-1,j,k+1,board,word); //回溯,恢复原状 board[i][j] = word[k]; //返回,很重要 return res; } };
-
剑指13,机器人的运动范围
//时间O(mn),空间O(mn) //标准dfs+剪枝,使用二维数组记录已访问过的位置 //注意,从左上到右下,只需关注右和下两个方向 class Solution { public: int movingCount(int m, int n, int k) { vector<vector<int>> vec(m,vector<int>(n)); return dfs(m,n,k,0,0,vec); } private: int dfs(int m, int n, int k,int i, int j, vector<vector<int>> &vec) { //如果越界,数位之和大于k,已访问过 if(i >= m || j >= n || digitSum(i)+digitSum(j) > k || vec[i][j]) return 0; //标记 vec[i][j] = 1; //递推 return 1 + dfs(m,n,k,i,j+1,vec) + dfs(m,n,k,i+1,j,vec); } //数位之和 int digitSum(int num) { int res = 0; int x; while(num) { x = num % 10; num /= 10; res += x; } return res; } }; //时间O(mn),空间O(mn) //标准bfs+剪枝,使用二维数组记录已访问过的位置 //熟记bfs套路 class Solution { public: int movingCount(int m, int n, int k) { queue<pair<int,int>> que; que.push({0,0}); int res = 0; vector<vector<int>> vec(m,vector<int>(n)); while(!que.empty()) { auto temp = que.front(); que.pop(); if(temp.first >= m || temp.second >= n || digitSum(temp.first)+digitSum(temp.second) > k || vec[temp.first][temp.second]) continue; ++res; vec[temp.first][temp.second] = 1; que.push({temp.first,temp.second+1}); que.push({temp.first+1,temp.second}); } return res; } private: //数位之和 int digitSum(int