leetcode之DFS+BFS+DSU刷题总结1
Posted nuist__NJUPT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode之DFS+BFS+DSU刷题总结1相关的知识,希望对你有一定的参考价值。
leetcode之dfs+bfs+dsu刷题总结1
1-所有可能的路径
题目链接:题目链接戳这里!!!
思路:dfs搜索所有路径,并用栈记录搜索轨迹。
class Solution
Stack<Integer> stack = new Stack<>() ;
List<List<Integer>> list = new ArrayList<>() ;
public List<List<Integer>> allPathsSourceTarget(int[][] graph)
dfs(0,graph) ;
return list ;
public void dfs(int x, int [][] graph)
stack.push(x) ;
if(x==graph.length-1)
list.add(new ArrayList<>(stack)) ;
for(int y : graph[x])
dfs(y,graph) ;
stack.pop() ;
2-判断二分图
题目链接:题目链接戳这里!!!
思路:dfs+染色法。
我们使用图搜索算法从各个连通域的任一顶点开始遍历整个连通域,遍历的过程中用两种不同的颜色对顶点进行染色,相邻顶点染成相反的颜色。这个过程中倘若发现相邻的顶点被染成了相同的颜色,说明它不是二分图;反之,如果所有的连通域都染色成功,说明它是二分图。
class Solution
public boolean isBipartite(int[][] graph)
int [] vis = new int [graph.length] ;
for(int i=0; i<graph.length; i++)
if(vis[i]==0 && !dfs(graph,i,1,vis))
return false ;
return true ;
public boolean dfs(int [][] graph, int x, int color, int [] vis)
if(vis[x]!=0)
return vis[x] == color ;
vis[x] = color ;
for(int y : graph[x])
if(!dfs(graph,y,-color,vis))
return false ;
return true ;
思路2:bfs+染色法
对于每个顶点,如果未被访问过,则入队,对于该顶点的所有邻接顶点,如果已经被染色,且颜色与当前颜色相同,则不是二分图,如果未被染色,则应染成和相邻顶点相同的颜色。
class Solution
public boolean isBipartite(int[][] graph)
int [] vis = new int [graph.length] ;
Queue<Integer> queue = new LinkedList<>() ;
for(int i=0; i<graph.length; i++)
if(vis[i]!=0)
continue ;
queue.add(i) ;
vis[i] = 1 ;
while(!queue.isEmpty())
int x = queue.poll() ;
for(int y : graph[x])
if(vis[y]==vis[x])
return false ;
if(vis[y]==0)
vis[y] = -vis[x] ;
queue.add(y) ;
return true ;
3-地图中的最高点
题目链接:题目链接戳这里!!!
思路:多源bfs
题目要求让矩阵中的最高高度最大,我们可以通过最大化每个格子的高度来做到这一点。由于任意相邻的格子高度差至多为 1,这意味着对于每个格子,其高度至多比其相邻格子中的最小高度多 1。
题目要求水域的高度必须为 0,因此水域的高度是已经确定的值,我们可以从水域出发,推导出其余格子的高度:
首先,计算与水域相邻的格子的高度。对于这些格子来说,其相邻格子中的最小高度即为水域的高度 0,因此这些格子的高度为 1。
然后,计算与高度为 1 的格子相邻的、尚未被计算过的格子的高度。对于这些格子来说,其相邻格子中的最小高度为 1,因此这些格子的高度为 2。
以此类推,计算出所有格子的高度。
记录下所有水域的位置,然后执行广度优先搜索,计算出所有陆地格子的高度,即为答案。
class Solution
int [] dx = -1,1,0,0 ;
int [] dy = 0,0,-1,1 ;
public int[][] highestPeak(int[][] isWater)
int [][] ans = new int [isWater.length][isWater[0].length] ;
for(int i=0; i<ans.length; i++)
Arrays.fill(ans[i], -1) ; //初始化所有顶点未被访问
Queue<int[]> queue = new ArrayDeque<int[]>() ;
for(int i=0; i<isWater.length; i++)
for(int j=0; j<isWater[0].length; j++)
if(isWater[i][j]==1)
ans[i][j] = 0 ;
queue.add(new int []i,j) ;
while(!queue.isEmpty())
int [] p = queue.poll() ;
for(int i=0; i<4; i++)
int tx = p[0] + dx[i] ;
int ty = p[1] + dy[i] ;
if(tx>=0 && ty>=0 && tx<isWater.length && ty<isWater[0].length && ans[tx][ty]==-1)
ans[tx][ty] = ans[p[0]][p[1]] + 1 ;
queue.add(new int []tx,ty) ;
return ans ;
4-所有路径
题目链接:题目链接戳这里!!!
思路:dfs+栈记录
从0号顶点出发,依次搜索相邻顶点,并用栈记录搜索轨迹。
class Solution
List<List<Integer>> list = new ArrayList<>() ;
Stack<Integer> stack = new Stack<>() ;
public List<List<Integer>> allPathsSourceTarget(int[][] graph)
dfs(graph,0) ;
return list ;
public void dfs(int [][] graph, int x)
stack.push(x) ;
if(x==graph.length-1)
list.add(new ArrayList<>(stack)) ;
for(int y : graph[x])
dfs(graph,y) ;
stack.pop() ;
5-多余的边
题目链接:题目链接戳这里!!!
思路:并查集
在一棵树中,边的数量比节点的数量少 1。如果一棵树有 n 个节点,则这棵树有 n−1 条边。这道题中的图在树的基础上多了一条边,因此边的数量也是 n。
树是一个连通且无环的无向图,在树中多了一条边之后就会出现环,因此多余的边即为导致环出现的边。
可以通过并查集寻找多余的边。初始时,每个节点都属于不同的连通分量。遍历每一条边,判断这条边连接的两个顶点是否属于相同的连通分量。
如果两个顶点属于不同的连通分量,则说明在遍历到当前的边之前,这两个顶点之间不连通,因此当前的边不会导致环出现,合并这两个顶点的连通分量。
如果两个顶点属于相同的连通分量,则说明在遍历到当前的边之前,这两个顶点之间已经连通,因此当前的边导致环出现,为多余的边,将当前的边作为答案返回。
class Solution
public int[] findRedundantConnection(int[][] edges)
int n = edges.length ;
int [] parent = new int [n+1] ;
for(int i=1; i<=n; i++)
parent[i] = i ;
for(int i=0; i<n; i++)
int [] edge = edges[i] ;
int node0 = edge[0], node1 = edge[1] ;
if(find(parent,node0)!=find(parent,node1))
union(parent,node0,node1) ;
else
return edge ;
return new int [] ;
public int find(int [] parent, int node)
if(node!=parent[node])
parent[node] = find(parent,parent[node]) ;
return parent[node] ;
public void union(int [] parent, int node1, int node0)
parent[parent[node1]] = find(parent,parent[node0]) ;
6-矩阵中的距离
题目链接:题目链接戳这里!!!
思路:bfs
首先将所有的0入队,然后多元广度优先搜索,如果其它相邻点未搜索过,则为当前点加1.
class Solution
int [] dx = -1,1,0,0 ;
int [] dy = 0,0,-1,1 ;
public int[][] updateMatrix(int[][] mat)
//广度优先搜索
int m = mat.length ;
int n = mat[0].length ;
Queue<int[]> queue = new LinkedList<int[]>() ;
int [][] ans = new int [m][n] ;
boolean [][] vis = new boolean [m][n] ;
for(int i=0; i<m; i++)
for(int j=0; j<n; j++)
if(mat[i][j] == 0)
queue.add(new int [] i,j) ;
vis[i][j] = true ;
while(!queue.isEmpty())
int [] edge = queue.poll() ;
for(int i=0; i<4; i++)
int tx = edge[0] + dx[i] ;
int ty = edge[1] + dy[i] ;
if(tx>=0 && ty>=0 && tx<m && ty<n && !vis[tx][ty])
ans[tx][ty] = ans[edge[0]][edge[1]] + 1 ;
queue.add(new int []tx,ty) ;
vis[tx][ty] = true ;
return ans ;
7-最小基因变化
题目链接:题目链接戳这里!!!
思路:bfs+剪枝
题目给定一个起始字符串start和一个目标字符串end, 其中start只能通过以下步骤变化为新的字符串。
每一次变化,都只能用"A", “C”, “G”, "T"里的任意一个字母替换当前字符串里的某一个字母。
替换后得到的新的字符串必须在给定的bank里。
明确这两点之后,我们很容易地想到这个题建模为树(具体来说,无权树),可知只不过这个树的子树会比较多,可以剪枝。
class Solution
public int minMutation(String start, String end, String[] bank)
Set<String> bankSet = new HashSet<>() ;
for(String str : bank)
bankSet.add(str) ;
String [] gene = "A","C","G","T" ;
Set<String> vis = new HashSet<>() ;
Queue<String> queue = new LinkedList<>() ;
vis.add(start) ;
queue.add(start) ;
int step = 0 ;
while(!queue.isEmpty())
int size = queue.size() ;
for(int k=0; k<size; k++)
String s leetcode之最短路径+记忆化dfs+bfs+动态规划刷题总结