leetcode之深度优先搜索刷题总结3
Posted nuist__NJUPT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode之深度优先搜索刷题总结3相关的知识,希望对你有一定的参考价值。
leetcode之深度优先搜索刷题总结3
1-找到最终的安全状态
题目链接:题目链接戳这里!!!
思路:dfs+三色标记法
根据题意,若起始节点位于一个环内,或者能到达一个环,则该节点不是安全的。否则,该节点是安全的。
我们可以使用深度优先搜索来找环,并在深度优先搜索时,用三种颜色对节点进行标记,标记的规则如下:
白色(用 0 表示):该节点尚未被访问;
灰色(用 1 表示):该节点位于递归栈中,或者在某个环上;
黑色(用 2 表示):该节点搜索完毕,是一个安全节点。
如果搜索过程中出现不安全的,即color>0且color=1的,则返回false。如果都是安全的,则标记为color=2
class Solution
public List<Integer> eventualSafeNodes(int[][] graph)
List<Integer> list = new ArrayList<>() ;
int [] color = new int [graph.length];
for(int i=0; i<graph.length; i++)
if(dfs(graph,color,i))
list.add(i) ;
return list ;
public boolean dfs(int [][]graph, int []color, int i)
if(color[i]>0)
return color[i]==2 ;
color[i] = 1 ;
for(int j : graph[i])
if(!dfs(graph,color,j))
return false ;
color[i] = 2 ;
return true ;
2-网络延迟时间
题目链接:题目链接戳这里!!!
思路:题目实际是求节点 K 到其他所有点中最远的距离,那么首先需要求出节点 K 到其他所有点的最短路,然后取最大值即可。
单源最短路径问题,我们使用Dijkstra算法。
首先,Dijkstra 算法需要存储各个边权,所以代码中使用了邻接矩阵 g[i][j] 存储从点 i 到点 j 的距离。若两点之间没有给出有向边,则初始化为 inf。
算法还需要记录所有点到源点的最短距离,代码中使用了 dist[i] 数组存储源点到点 i 的最短距离,初始值也全部设为 inf。由于本题源点为 K,所以该点距离设为 0。
其次,Dijkstra 算法需要标记某一节点是否已确定了最短路,在代码中使用了vis[i] 数组存储,若已确定最短距离,则值为 true,否则值为 false。
算法需要从当前全部未确定最短路的点中,找到距离源点最短的点,通过该点更新其他所有点距离源点的最短距离。
之所以 inf 设置为 Integer.MAX_VALUE / 2 ,是因为在更新最短距离的时候,要有两个距离相加,为了防止溢出 int 型,所以除以 2。
class Solution
public int networkDelayTime(int[][] times, int n, int k)
int INF = Integer.MAX_VALUE / 2 ;
int [][]g = new int [n][n] ;
for(int i=0; i<n; i++)
Arrays.fill(g[i],INF) ;
for(int [] t : times) //数组g存储边的权值
g[t[0]-1][t[1]-1] = t[2] ;
int [] dist = new int [n] ; //记录源点到目标节点的最短距离
Arrays.fill(dist,INF) ;
dist[k-1] = 0 ;
boolean [] vis = new boolean[n] ; //记录当前节点是否已经确定为最短路径
for(int i=0; i<n; i++)
int x = -1 ;
for(int y=0; y<n; y++)
if(!vis[y] &&(x==-1 || dist[y]<dist[x]))
x = y ;
vis[x] = true ;
for(int y=0; y<n; y++)
dist[y] = Math.min(dist[y],dist[x]+g[x][y]) ;
int res = Integer.MIN_VALUE ;
for(int value : dist)
res = Math.max(value,res) ;
return res == INF ? -1 : res ;
3-跳跃游戏III
题目链接:题目链接戳这里!!!
思路:记忆化搜索,每次可以向两个方向搜索,如果搜索重复位置,则中止当前搜索,如果搜索的当前值为0,则标记可以跳到,即flag=true。
AC代码如下:
class Solution
boolean flag ;
public boolean canReach(int[] arr, int start)
//记忆化搜索
boolean [] vis = new boolean [arr.length] ;
flag = false ;
dfs(arr, start, vis);
return flag;
public void dfs(int []arr, int start, boolean [] vis)
if(arr[start]==0)
flag=true ;
return ;
if(vis[start])
return ;
vis[start] = true ;
if(start+arr[start]<=arr.length-1)
dfs(arr,start+arr[start],vis) ;
if(start-arr[start]>=0)
dfs(arr,start-arr[start],vis) ;
4-找到所有的农场组
题目链接:题目链接戳这里!!!
思路:搜索+标记,每一轮搜索到的连通块,更新下标的最大值,即是右下角。每一次将第一次搜索的下标和右下角的下标分别存入结果集合中,如果当前下标就是右下标,则直接返回当前下标。
class Solution
int [] dx = 0,0,-1,1 ;
int [] dy = 1,-1,0,0 ;
int maxX , maxY ;
List<Integer> list = new ArrayList<>() ;
public int[][] findFarmland(int[][] land)
for(int i=0; i<land.length; i++)
for(int j=0; j<land[0].length; j++)
if(land[i][j]==1)
maxX = Integer.MIN_VALUE ;
maxY = Integer.MIN_VALUE ;
list.add(i) ;
list.add(j) ;
dfs(land,i,j) ;
if(maxX!=Integer.MIN_VALUE)
list.add(maxX) ;
else
list.add(i) ;
if(maxY!=Integer.MIN_VALUE)
list.add(maxY) ;
else
list.add(j) ;
int [][] ans = new int [list.size()/4][4] ;
int k = 0 ;
for(int i=0;i<ans.length; i++)
for(int j=0; j<ans[0].length; j++)
ans[i][j] = list.get(k) ;
k ++ ;
return ans ;
public void dfs(int [][] land, int x, int y)
land[x][y] = 0 ;
for(int i=0; i<4; i++)
int tx = x + dx[i] ;
int ty = y + dy[i] ;
if(tx<0 || ty<0 || tx>land.length-1 || ty>land[0].length-1)
continue ;
if(land[tx][ty]==1)
maxX = Math.max(maxX, tx) ;
maxY = Math.max(maxY, ty) ;
dfs(land, tx, ty) ;
5-传递信息
题目链接:题目链接戳这里!!!
思路:将二维关系数组转换成有向图,从原始位置开始搜索,每次搜索step+1,如果搜索k次后,当前的编号为n-1,表示经过 k 轮传递到编号为 n-1 的小伙伴处,则ways++。
class Solution
int ways;
List<List<Integer>> edges;
public int numWays(int n, int[][] relation, int k)
ways = 0;
edges = new ArrayList<List<Integer>>();
for (int i = 0; i < n; i++)
edges.add(new ArrayList<Integer>());
for (int[] edge : relation)
edges.get(edge[0]).add(edge[1]);
dfs(0, 0,n,k);
return ways;
public void dfs(int index, int steps,int n, int k)
if (steps == k)
if (index == n - 1)
ways++;
return;
List<Integer> list = edges.get(index);
for (int nextIndex : list)
dfs(nextIndex, steps + 1, n, k);
思路:动态规划
dp[k][n-1]表示经过 k 轮传递到编号为 n-1 的小伙伴处的方案数
递推表达式:dp[i+1][edge[1]] += dp[i][edge[0]] ;
class Solution
public int numWays(int n, int[][] relation, int k)
int [][] dp = new int [k+1][n] ;
dp[0][0] = 1 ;
for(int i=0; i<k; i++)
for(int [] edge : relation)
dp[i+1][edge[1]] += dp[i][edge[0]] ;
return dp[k][n-1] ;
6-省份数量
题目链接:题目链接戳这里!!!
思路:判断每个省份是否已经搜索,若没搜索,则进行搜索,每轮搜索进行标记为已搜索,每轮搜索累加省份数量,直至搜索完成。
class Solution
boolean [] vis ;
public int findCircleNum(int[][] isConnected)
int povince = isConnected.length ;
int cnt = 0 ;
vis = new boolean[povince] ;
for(int i=0; i<povince; i++)
if(!vis[i])
dfs(isConnected,i,vis,povince) ;
cnt ++ ;
return cnt ;
public void dfs(int [][] isConnected, int i, boolean[] vis, int povince)
vis[i] = true ;
for(int j=0; j<povince; j++)
if(isConnected[i][j]==1 && !vis[j])
dfs(isConnected,j,vis,povince) ;
7-机器人的运动范围
题目链接:题目链接戳这里!!!
思路:沿着四个方向进行搜索,如果如果当前位置满足搜索条件,就累加1,继续搜索下去,直至不能搜索。
class Solution
int [] dx = 0,0,-1,1 ;
int [] dy = -1,1,0,0 ;
int cnt ;
boolean [][] vis ;
public int movingCount(int m, int n, int k)
cnt = 0 ;
vis = new boolean[m][n] ;
dfs(0,0,m,n,k,vis) ;
return cnt ;
public void dfs(int i, int j, int m, int n, int k, boolean[][] vis)
vis[i][j] = true ;
cnt ++ ;
for(int x=0; x<4; x++)
int tx = i + dx[x] ;
int ty = j + dy[x] ;
if(tx以上是关于leetcode之深度优先搜索刷题总结3的主要内容,如果未能解决你的问题,请参考以下文章