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+动态规划刷题总结

LeetCode刷题之BFS和DFS

LeetCode刷题记录

LeetCode刷题记录

leetcode之深度优先搜索刷题总结1

LeetCode刷题记录