classSolution{public:voidsolveSudoku(vector<vector<char>>& board){backtrack(board,0,0);}// 回溯算法boolbacktrack(vector<vector<char>>& board,int i,int j){// 终止条件if(i ==9)returntrue;// 一行一行的填if(j ==9){returnbacktrack(board, i +1,0);}// 如果是填好的数字, 不用管if(board[i][j]!='.'){returnbacktrack(board, i, j +1);}// 选择列表, 开始从 1 到 9 填入for(char ch ='1'; ch <='9';++ch){// 看数字是否有效if(!isValid(board, i, j, ch))continue;// 做选择
board[i][j]= ch;// 下一层选择if(backtrack(board, i, j +1)){returntrue;};// 撤销选择
board[i][j]='.';}// 没有找到可行解returnfalse;}// 判断填的地方是否有效boolisValid(vector<vector<char>>& board,int row,int col,char val){for(int i =0; i <9;++i){// 判断行是否存在重复if(board[row][i]== val)returnfalse;// 判断列是否存在重复if(board[i][col]== val)returnfalse;// 判断 3X3 是否重复if(board[row /3*3+ i /3][col /3*3+ i %3]== val)returnfalse;}returntrue;}};
🥂 46. 全排列 [无重数组] [排列] (回溯)
classSolution{private:
vector<vector<int>> res;// 存放最终的排列组合
vector<int> track;// 存放当前路径上的节点
vector<int> used;// 选择列表, 记录第 i 个节点是否被选择过int n;// 节点个数public:
vector<vector<int>>permute(vector<int>& nums){
n = nums.size();
used =vector<int>(n);// 选择列表初始化backtrack(nums);return res;}// 回溯算法voidbacktrack(vector<int>& nums){// 结束条件if(track.size()== n){
res.push_back(track);return;}// 选择列表, 一个个开始选择for(int i =0; i < n;++i){// 如果第 i 个数已经被使用过, 则跳过if(used[i]==1)continue;// 做选择, 更新选择列表
used[i]=1;
track.push_back(nums[i]);// 下一层选择backtrack(nums);// 撤消选择, 更新选择列表
used[i]=0;
track.pop_back();}}};
🥂 47. 全排列Ⅱ [有重数组] [排列] (回溯)
classSolution{private:
vector<vector<int>> res;// 存放符合排列
vector<int> track;// 当前遍历的元素
vector<int> used;// 第 i 个元素有无被使用过int n;// 元素个数public:
vector<vector<int>>permuteUnique(vector<int>& nums){
n = nums.size();sort(nums.begin(), nums.end());
used =vector<int>(n);backtrack(nums);return res;}// 回溯算法voidbacktrack(vector<int>& nums){// 终止条件if(track.size()== n){
res.push_back(track);return;}// 选择列表, 从 0 到 end 依次选择for(int i =0; i < n;++i){// 判断有无被选过if(used[i])continue;// 判断是否分支重复, 剪枝// 确保相同元素中 i-1 一定比 i 先使用if(i >0&& nums[i]== nums[i -1]&&!used[i -1])continue;// 做选择
track.push_back(nums[i]);
used[i]=1;// 下一层选择backtrack(nums);// 撤消选择
track.pop_back();
used[i]=0;}}};
🥂 51. N皇后 [矩阵] [排列] (回溯)
classSolution{private:
vector<vector<string>> res;// 存放符合的摆放方案
vector<string> track;// 初始化棋盘int n;// 棋盘边长public:
vector<vector<string>>solveNQueens(int n){this->n = n;
track =vector<string>(n,string(n,'.'));backtrack(0);return res;}// 回溯算法voidbacktrack(int row){// 结束条件if(row == n){
res.push_back(track);return;}// 选择列表, 从左到右选择一行for(int col =0; col < n;++col){// 判断是否可以选择if(!isValid(row, col))continue;// 做选择, 更新选择列表
track[row][col]='Q';// 下一层选择backtrack(row +1);// 撤销选择, 更新选择列表
track[row][col]='.';}}// 判断棋盘摆放的位置是否有效boolisValid(int row,int col){int n = track.size();// 列满足for(int i = row -1; i >=0;--i){if(track[i][col]=='Q')returnfalse;}// 右上斜向满足for(int i = row -1, j = col +1; i >=0&& j < n;--i,++j){if(track[i][j]=='Q')returnfalse;}// 左上斜向满足for(int i = row -1, j = col -1; i >=0&& j >=0;--i,--j){if(track[i][j]=='Q')returnfalse;}returntrue;}};
🥂 52. N皇后Ⅱ [矩阵] [排列] (回溯)
classSolution{private:int res =0;// 符合的摆放方案数量
vector<string> track;// 初始化棋盘int n;// 棋盘边长public:inttotalNQueens(int n){this->n = n;
track =vector<string>(n,string(n,'.'));backtrack(0);return res;}// 回溯算法voidbacktrack(int row){// 结束条件if(row == n){
res++;return;}// 选择列表, 从左到右选择一行for(int col =0; col < n;++col){// 判断是否可以选择if(!isValid(row, col))continue;// 做选择, 更新选择列表
track[row][col]='Q';// 下一层选择backtrack(row +1);// 撤销选择, 更新选择列表
track[row][col]='.';}}// 判断棋盘摆放的位置是否有效boolisValid(int row,int col){int n = track.size();// 列满足for(int i = row -1; i >=0;--i){if(track[i][col]=='Q')returnfalse;}// 右上斜向满足for(int i = row -1, j = col +1; i >=0&& j < n;--i,++j){if(track[i][j]=='Q')returnfalse;}// 左上斜向满足for(int i = row -1, j = col -1; i >=0&& j >=0;--i,--j){if(track[i][j]=='Q')returnfalse;}returntrue;}};
🍺 DFS
🍻 岛屿问题
🥂 200. 岛屿数量 [矩阵] [岛屿] (DFS)
classSolution{private:int m, n;// 地图的宽高int res;// 岛屿数量
vector<vector<int>> dirts ={{-1,0},{1,0},{0,1},{0,-1}};// 方向public:intnumIslands(vector<vector<char>>& grid){
m = grid.size(), n = grid[0].size();for(int i =0; i < m;++i){for(int j =0; j < n;++j){if(grid[i][j]=='1'){DFS(grid, i, j);
res++;}}}return res;}// DFSvoidDFS(vector<vector<char>>& grid,int i,int j){if(i <0|| i >= m || j <0|| j >= n)return;if(grid[i][j]=='0')return;// 将已遍历岛屿沉默
grid[i][j]='0';// 探寻四周的元素for(auto& dirt : dirts){DFS(grid, i + dirt[0], j + dirt[1]);}}};
🥂 694. 不同岛屿的数量 [矩阵] [岛屿] (DFS) (序列化)
classSolution{private:int m, n;// 地图的宽高int res =0;// 不同岛屿的数量
string track;// 序列化字符串路径
vector<vector<int>> dirts ={{-1,0},{1,0},{0,1},{0,-1}};// 方向
unordered_set<string> uset;// 记录进入岛屿的序列化字符串 public:intnumDistinctIslands(vector<vector<int>>& grid){
m = grid.size(), n = grid[0].size();for(int i =0; i < m;++i){for(int j =0; j < n;++j){if(grid[i][j]==1){
track ="";DFS(grid, i, j,0);
uset.insert(track);}}}return uset.size();}// DFS voidDFS(vector<vector<int>>& grid,int i,int j,int idx){if(i <0|| i >= m || j <0|| j >= n)return;if(grid[i][j]==0)return;// 将陆地淹没
grid[i][j]=0;// 进入岛屿, 并序列化路径
track +=to_string(idx)+",";// 向四周扩散for(int d_idx =0; d_idx < dirts.size(); d_idx++){DFS(grid, i + dirts[d_idx][0], j + dirts[d_idx][1], d_idx);}// 退出岛屿, 并序列化路径
track +=to_string(-idx)+",";}};
🥂 695. 岛屿的最大面积 [矩阵] [岛屿] (DFS)
classSolution{private:int m, n;// 地图的面积int res =0;// 岛屿的最大面积, 当前面积
vector<vector<int>> dirts ={{-1,0},{1,0},{0,1},{0,-1}};// 方向public:intmaxAreaOfIsland(vector<vector<int>>& grid){
m = grid.size(), n = grid[0].size();for(int i =0; i < m;++i){for(int j =0; j < n;++j){if(grid[i][j]==1){
res =max(res,DFS(grid, i, j));}}}return res;}// DFSintDFS(vector<vector<int>>& grid,int i,int j){// 越界或海水if(i <0|| i >= m || j <0|| j >= n)return0;if(grid[i][j]==0)return0;int cur =1;// 将陆地淹没
grid[i][j]=0;// 向四周扩散for(auto& dirt : dirts){
cur +=DFS(grid, i + dirt[0], j + dirt[1]);}return cur;}};
🥂 1020. 飞地的数量 [矩阵] [岛屿] (DFS)
classSolution{private:int m, n;// 地图大小int res =0;// 飞地大小bool iscount;// 是否开始统计陆地
vector<vector<int>> dirts ={{-1,0},{1,0},{0,1},{0,-1}};// 方向public:intnumEnclaves(vector<vector<int>>& grid){
m = grid.size(), n = grid[0].size();// 先把沿海的岛给阉淹了for(int i =0; i < m;++i){DFS(grid, i,0);DFS(grid, i, n -1);}for(int j =0; j < n;++j){DFS(grid,0, j);DFS(grid, m -1, j);}// 统计下中间还剩多少飞岛
iscount =true;for(int i =1; i < m -1;++i){for(int j =1; j < n -1;++j){if(grid[i][j]==1){DFS(grid, i, j);}}}return res;}// DFSvoidDFS(vector<vector<int>>& grid,int i,int j){if(i <0|| i >= m || j <0|| j >= n)return;if(grid[i][j]==0)return;// 将陆地淹没
grid[i][j]=0;if(iscount) res++;// 向四周扩散for(auto& dirt : dirts){DFS(grid, i + dirt[0], j + dirt[1]);}}};
🥂 1254. 统计封闭岛屿的数目 [矩阵] [岛屿] (DFS)
classSolution{private:int m, n;// 地图的宽高int res =0;// 岛屿数量
vector<vector<int>> dirts ={{-1,0},{1,0},{0,1},{0,-1}};// 方向public:intclosedIsland(vector<vector<int>>& grid){
m = grid.size(), n = grid[0].size();// 先把沿海的岛给阉淹了for(int i =0; i < m;++i){DFS(grid, i,0);DFS(grid, i, n -1);}for(int j =0; j < n;++j){DFS(grid,0, j);DFS(grid, m -1, j);}// 统计下中间还剩多少岛for(int i =1; i < m -1;++i){for(int j =1; j < n -1;++j){if(grid[i][j]==0){DFS(grid, i, j);
res++;}}}return res;}// DFSvoidDFS(vector<vector<int>>& grid,int i,int j){if(i <0|| i >= m || j <0|| j >= n)return;if(grid[i][j]==1)return;// 将陆地淹没
grid[i][j]=1;// 向四周扩散for(auto& dirt : dirts){DFS(grid, i + dirt[0], j + dirt[1]);}}};
🥂 1905. 统计子岛屿 [矩阵] [岛屿] (DFS)
classSolution{private:int m, n;// 地图的宽高int res =0;// 子岛屿数量
vector<vector<int>> dirts ={{-1,0},{1,0},{0,1},{0,-1}};// 方向public:intcountSubIslands(vector<vector<int>>& grid1, vector<vector<int>>& grid2){
m = grid1.size(), n = grid1[0].size();// 先找出不是子岛屿的岛for(int i =0; i < m;++i){for(int j =0; j < n;++j){if(grid1[i][j]==0&& grid2[i][j]==1){DFS(grid2, i, j);}}}// 统计剩下的岛屿for(int i =0; i < m;++i){for(int j =0; j < n;++j){if(grid2[i][j]==1){DFS(grid2, i, j);
res++;}}}return res;}// DFSvoidDFS(vector<vector<int>>& grid,int i,int j){if(i <0|| i >= m || j <0|| j >= n)return;if(grid[i][j]==0)return;// 将陆地淹没
grid[i][j]=0;// 向四周扩散for(auto& dirt : dirts){DFS(grid, i + dirt[0], j + dirt[1]);}}};