微网站页面自助建站系统官方版
news/
2025/9/25 22:53:13/
文章来源:
微网站页面,自助建站系统官方版,北京空间优化平台,成都网站建设服务功能目录深搜200. 岛屿数量695. 岛屿的最大面积130. 被围绕的区域547. 省份数量417. 太平洋大西洋水流问题回溯广搜111. 二叉树的最小深度752. 打开转盘锁深搜与广搜结合934. 最短的桥深搜
深搜DFS#xff0c;在搜索到一个新节点时#xff0c;立即对该新节点进行遍历#xff0c… 目录深搜200. 岛屿数量695. 岛屿的最大面积130. 被围绕的区域547. 省份数量417. 太平洋大西洋水流问题回溯广搜111. 二叉树的最小深度752. 打开转盘锁深搜与广搜结合934. 最短的桥 深搜
深搜DFS在搜索到一个新节点时立即对该新节点进行遍历需要用到栈实现或者使用与栈等价的递归实现。 深搜也可以用来检测环路记录每个遍历过的节点的父节点若有一个节点被再次遍历且父节点不同则说明有环。 有时我们可能会需要对已经搜索过的节点进行标记以防止在遍历时重复搜索某个节点这种做法叫做状态记录或者记忆化。
200. 岛屿数量
class Solution {
public:void dfs(vectorvectorchar grid,int m,int n,int i,int j){//如果越界或者为海域退出if(i 0 || i m || j 0 || j n || grid[i][j] 0) return;//标记为海域grid[i][j] 0;dfs(grid,m,n,i-1,j);dfs(grid,m,n,i1,j);dfs(grid,m,n,i,j-1);dfs(grid,m,n,i,j1);return ;}int numIslands(vectorvectorchar grid) {int m grid.size();int n grid[0].size();int time 0;for(int i 0; i m; i){for(int j 0; j n; j){if(grid[i][j] 1){dfs(grid,m,n,i,j);time;}}}return time;}
};695. 岛屿的最大面积
一般来说深搜可以分为主函数和辅助函数。 主函数用于遍历所有的所有搜索位置判断是否可以开始搜索如果可以即用辅助函数进行搜索。 辅助函数负责深搜的递归调用或者(栈)实现。
class Solution {
public:vectorint direction {-1,0,1,0,-1};//辅助函数int dfs(vectorvectorint grid, int r, int c){if(grid[r][c] 0) return 0;//否则清除标志grid[r][c] 0;//此时岛屿已经有1面积了接下来进行对四个方向进行深搜int x,y,area 1;for(int i 0; i 4; i){//新起点x r direction[i];y c direction[i1];//如果不越界则继续深搜if(x 0 x grid.size() y 0 y grid[0].size())area dfs(grid,x,y);}//最后返回以rc为起点的岛屿面积并且在地图上清除这个岛屿防止多次搜索。return area;}//主函数int maxAreaOfIsland(vectorvectorint grid) {if(grid.empty() || grid[0].empty()) return 0;int max_area 0;for(int i 0; i grid.size(); i){for(int j 0; j grid[0].size(); j){if(grid[i][j] 1){max_area max(max_area,dfs(grid,i,j));}}}return max_area;}
};辅助函数还可以写成这样我更倾向于这种写法
//辅助函数
int dfs(vectorvectorint grid, int r, int c)
{//如果该点越界或者为海域退出递归if(r 0 || r grid.size() || c 0 || c grid[0].size() || grid[r][c] 0) return 0;//否则说明该点为岛屿面积1,同时清除记录grid[r][c] 0;//返回以该点搜索起点的面积结果return 1 dfs(grid,r-1,c) dfs(grid,r,c1) dfs(grid,r1,c) dfs(grid,r,c-1);
}130. 被围绕的区域
class Solution {
public:void dfs(vectorvectorchar board,int m,int n,int i,int j){//递归退出条件if(i 0 || i m || j 0 || j n || board[i][j] X || board[i][j] A) return;//否则进行标记然后继续深搜board[i][j] A;dfs(board,m,n,i-1,j);dfs(board,m,n,i1,j);dfs(board,m,n,i,j-1);dfs(board,m,n,i,j1);return;}void solve(vectorvectorchar board) {int m board.size();int n board[0].size();//用dfs将边界的相连的0全部置为Afor(int i 0; i m ; i){dfs(board,m,n,i,0);dfs(board,m,n,i,n-1);}for(int j 0; j n ; j){dfs(board,m,n,0,j);dfs(board,m,n,m-1,j);}//进行覆盖操作只有为A的不进行覆盖for(int i 0; i m; i){for(int j 0; j n; j){if(board[i][j] A) board[i][j] O;else board[i][j] X;}}return;}
};547. 省份数量
分析求无向图中的连通域个数输入矩阵即为无向图的邻接矩阵
深搜思路遍历所有城市对于每个城市如果该城市没有被访问过则从该城市开始深度优先搜索通过矩阵得到与该城市直接相连的城市有哪些这些城市与该城市属于同一个连通分量然后对这些城市继续深搜直到同一个连通分量的所有城市都被访问到就可以得到一个省份。
class Solution {
public:void dfs(vectorvectorint isConnected,int i,vectorbool visited) {for(int j 0; j isConnected.size(); j){//继续遍历与顶点相邻的顶点使用visited数组防止重复访问if(isConnected[i][j] 1 visited[j] false){//标记当前访问过的顶点visited[j] true;dfs(isConnected,j,visited);}}return;}int findCircleNum(vectorvectorint isConnected) {int n isConnected.size();int count 0;//标识顶点是否被访问vectorbool visited(n,false);for(int i 0; i n; i){//如果当前顶点没有被访问说明是一个新的连通域遍历这个连通域且计数1if(!visited[i]){dfs(isConnected,i,visited);count;}}return count;}
};417. 太平洋大西洋水流问题
1、边界可以去往旁边的一个海洋 也就是说边界与海洋是连通的所以需要从外往内扩散获得与边界连通的区域也就是高度相等或者高度比当前区域高的位置 2、为了防止重复遍历添加visited数组 3、将连通的部分放到两个子集中一个是和太平洋连通的区域一个是和大西洋连通的区域。然后对两个求交集即可。
class Solution {
public:vectorint direction{-1,0,1,0,-1};bool Isvaild(int x,int y,vectorvectorint matrix){if(x 0 x matrix.size() y 0 y matrix[0].size()) return true;else return false;}//辅函数void dfs(vectorvectorint matrix,vectorvectorbool can_reach,int r,int c){//如果这个点遍历过了退出if(can_reach[r][c]) return;can_reach[r][c] true;int x,y;//向四个方向扩散for(int i 0; i 4; i){x r direction[i];y c direction[i1];if(Isvaild(x,y,matrix) matrix[r][c] matrix[x][y])dfs(matrix,can_reach,x,y);}}//主函数vectorvectorint pacificAtlantic(vectorvectorint matrix){if(matrix.empty() || matrix[0].empty()) return {};vectorvectorint ans;int m matrix.size();int n matrix[0].size();//记录能与p洋连通的区域vectorvectorbool can_reach_p(m,vectorbool(n,false));//记录能与a洋连通的区域vectorvectorbool can_reach_a(m,vectorbool(n,false));//遍历上下边界for(int i 0; i m; i){//扩散深搜dfs(matrix,can_reach_p,i,0);dfs(matrix,can_reach_a,i,n-1);}//遍历左右边界for(int j 0; j n; j){//扩散深搜dfs(matrix,can_reach_p,0,j);dfs(matrix,can_reach_a,m-1,j);}//将所有遍历结果进行取交集for(int i 0; i m; i){for(int j 0; j n; j){if(can_reach_p[i][j] can_reach_a[i][j])ans.push_back(vectorint{i,j});}}return ans;}
};回溯
回溯之前已经做过一些题目了都是一些经典题目直接放在这儿。 算法题复习回溯
广搜
模板如下
//计算从起点start到终点target的最短距离
int BFS(Node start,Node target)
{queueNode q; //核心数据结构SetNode visited; //避免走回头路q.push(start); //将起点加入队列visited.insert(start);int steps 0; //记录扩散步数while(!q.empty()){//更新步数step;int sz q.size();//将当前队列中的所有节点向四周扩散for(int i 0; i sz; i){Node cur q.front();q.pop();//判断是否到达终点if(cur target) return step;//将cur相邻的节点加入队列for(Node x: cur.adj()){//如果没有遍历过if(visited.find(x) visited.end()){q.push(x);visited.insert(x);}}}}
}cur.adj表示与cur相邻的节点。visited主要是防止走回头路二叉树结构没有子节点到父节点的指针所以不会走回头路不需要visited。 不同于深度优先搜索广搜是一层一层遍历的因此需要用到先入先出的队列常常用来处理最短路径问题。
深搜和广搜都可以处理可达性问题即从一个节点开始是否能到达另一个节点。因为深搜可以利用递归快速实现所以很多人习惯使用深搜。但是实际工程中很少使用递归容易产生栈溢出。
111. 二叉树的最小深度
startroot根节点 target最靠近根节点的的叶子节点
if(cur.left nullptr cur.right nullptr) //到达了叶子节点class Solution {
public:int minDepth(TreeNode* root) {int result 0;queueTreeNode* que;if(root nullptr) return 0;que.push(root);while(!que.empty()){result;int sz que.size();for(int i 0; i sz; i){TreeNode* cur que.front();que.pop();//如果走到终点返回结果if(cur-left nullptr cur-right nullptr) return result;//否则继续if(cur-left ! nullptr) que.push(cur-left);if(cur-right ! nullptr) que.push(cur-right);}}return result;}
};752. 打开转盘锁
计算从初始状态“0000”拨出目标状态的最少次数如果永远无法拨出则返回-1. 列表 deadends 包含了一组死亡数字一旦拨轮的数字和列表里的任何一个元素相同这个锁将会被永久锁定无法再被旋转。 从0000开始按照广度的思想转一次有8种可能 1000、9000、0100、0900、… 可以抽象成一幅图每个节点有8个相邻的节点求最短距离此时可以用上BFS。 使用下面的初步代码是按照BFS来寻找的最小密码组合不过显然是有问题的。
class Solution {
public:string plusOne(string s,int j){string result s;if(result[j] 9) result[j] 0;else result[j] result[j] 1;return result;}string minusOne(string s,int j){string result s;if(result[j] 0) result[j] 9;else result[j] result[j] - 1;return result;}int openLock(vectorstring deadends, string target) {queuestring q;string start 0000;q.push(start);int time 0;while(!q.empty()){time;int sz q.size();for(int i 0; i sz; i){string cur q.front();q.pop();//判断是否到达终点if(cur target) return time;//将一个节点相邻的节点加入队列for(int j 0; j 4; j){string up plusOne(cur,j);q.push(up);string down minusOne(cur,j);q.push(down);}}}return time;}
};存在的问题如下 1、会走回头路比如0000拨到1000但是等从队列中拿出1000还会拨出0000 2、没有对deadends进行处理按道理来说这些死亡密码不能出现遇到这些密码的时候需要跳过。 修改后的代码如下
class Solution {
public:string plusOne(string s,int j){string result s;if(result[j] 9) result[j] 0;else result[j] result[j] 1;return result;}string minusOne(string s,int j){string result s;if(result[j] 0) result[j] 9;else result[j] result[j] - 1;return result;}int openLock(vectorstring deadends, string target) {//记录需要跳过的死亡密码setstring deads;for(string s : deadends) deads.insert(s);//记录已经穷举过的密码防止走回头陆setstring visited;queuestring q;string start 0000;q.push(start);visited.insert(start);int time 0;while(!q.empty()){int sz q.size();for(int i 0; i sz; i){string cur q.front();q.pop();//判断是否合法if(deads.find(cur) ! deads.end()) continue; //判断是否到达终点if(cur target) return time;//将一个节点相邻的节点加入队列如果是存在过的就不需要加入队列了for(int j 0; j 4; j){string up plusOne(cur,j);if(visited.find(up) visited.end()){q.push(up);visited.insert(up);}string down minusOne(cur,j);if(visited.find(down) visited.end()){q.push(down);visited.insert(down);}}}time;}return -1;}
};深搜与广搜结合
934. 最短的桥
class Solution {
public:vectorint direction{-1,0,1,0,-1};void dfs(vectorvectorint A,queuepairint,int points,int m,int n,int i,int j){//如果越界了或者遍历过了不继续向深处遍历if(i 0 || j 0 || i m || j n || A[i][j] 2) return;//如果是海域,插入队列中if(A[i][j] 0){points.push({i,j});return ;}A[i][j] 2;//继续深度遍历dfs(A,points,m,n,i-1,j);dfs(A,points,m,n,i1,j);dfs(A,points,m,n,i,j-1);dfs(A,points,m,n,i,j1);return;} int shortestBridge(vectorvectorint A) {int m A.size();int n A[0].size();//深度遍历寻找第一个岛屿int flag 0;queuepairint,int points;for(int i 0; i m; i){if(flag 1) break;for(int j 0; j n; j){//深度遍历完一个岛屿后立即退出if(A[i][j] 1){flag 1;dfs(A,points,m,n,i,j);break;}}}//开始广度遍历int level 0;while(!points.empty()){int N points.size();level;while(N--){auto [r,c] points.front();points.pop();//向四周广度遍历for(int k 0; k 4; k){int x r direction[k];int y c direction[k1];if(x 0 x m y 0 y n){//如果还是第1个岛屿if(A[x][y] 2) continue;if(A[x][y] 1) return level;//如果还是0则是继续入队列points.push({x,y});//将该坐标并入第1个岛屿A[x][y] 2;}}}}return level;}
};
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/917656.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!