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<0 || ty<0 || tx>m-1 || ty>n-1 || sum(tx,ty)>k){
                continue ;
            }
            if(!vis[tx][ty]){
                dfs(tx,ty,m,n,k,vis) ;
            }
        }
    }
    public int sum (int tx, int ty){
        int res = 0 ;
        String s1 = String.valueOf(tx) ;
        String s2 = String.valueOf(ty) ;
        for(int i=0; i<s1.length(); i++){
            res += (s1.charAt(i)-'0') ;
        }
        for(int i=0; i<s2.length(); i++){
            res += (s2.charAt(i)-'0') ;
        }
        return res ;

    }
}

在这里插入图片描述

8-水域大小
题目链接:题目链接戳这里!!!

思路:沿着8个方向搜索,每轮搜索记录水域大小,最后对水域大小进行升序排序即可。

class Solution {
    int cnt ;
    int [] dx = {-1,-1,-1,0,0,1,1,1} ;
    int [] dy = {-1,0,1,-1,1,-1,0,1} ;
    public int[] pondSizes(int[][] land) {
        List<Integer> list = new ArrayList<>() ;
        for(int i=0; i<land.length; i++){
            for(int j=0; j<land[0].length; j++){
                if(land[i][j]==0){
                    cnt = 0 ;
                    dfs(land,i,j) ;
                    list.add(cnt) ;
                }
            }
        }
        int [] res = new int [list.size()] ;
        int j = 0 ;
        for(int value : list){
            res[j++] = value ;
        }
        Arrays.sort(res) ;
        return res ;
    }
    public void dfs(int [][] land, int x, int y){
        land[x][y]=1 ;
        cnt ++ ;
        for(int i=0;i<8; 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]==0){
                dfs(land,tx,ty) ;
            }

        }

    }
}

在这里插入图片描述

9-岛屿的最大面积
题目链接:题目链接戳这里!!!

思路:沿着四个方向搜索,每轮搜索对比岛屿面积,找出最大的岛屿面积即可。

class Solution {
    int cnt ;
    int [] dx = {-1,1,0,0} ;
    int [] dy = {0,0,-1,1} ;
    public int maxAreaOfIsland(int[][] grid) {
        int max = 0 ;
        for(int i=0; i<grid.length; i++){
            for(int j=0; j<grid[0].length; j++){
                if(grid[i][j]==1){
                    cnt = 0 ;
                    dfs(grid,i,j) ;
                    max = Math.max(max,cnt) ;
                }
            }
        }
        return max ;
    }
    public void dfs(int [][]grid, int x, int y){
        grid[x][y] = 0 ;
        cnt ++ ;
        for(int i=0;  i<4; i++){
            int tx = x + dx[i] ;
            int ty = y + dy[i] ;
            if(tx<0 || ty<0 || tx>grid.length-1 || ty>grid[0].length-1){
                continue ;
            }
            if(grid[tx][ty]==1){
                dfs(grid,tx,ty) ;
            }
        }
    }
}

在这里插入图片描述

10-课程顺序
题目链接:题目链接戳这里!!!

思路:将课程表转换成有向图,对有向图进行搜索,如果有环,则说明无法学完所有课程,否则可以学完所有课程。

vis数组是标记数组。
vis为0时,代表尚未学习该课程
vis为1时,代表此轮搜索中已学习过该课程,代表有环
vis为-1时,代表上轮搜索中学习了该课程,无环。

class Solution {
    List<List<Integer>> edges ;
    List<Integer>res = new ArrayList<>() ;
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        edges = new ArrayList<>() ;
        int [] vis = new int [numCourses] ;
        for(int i=0; i<numCourses; i++){
            edges.add(new ArrayList<>()) ;
        }
        for(int []edge : prerequisites){
            edges.get(edge[1]).add(edge[0]) ;
        }
        for(int i=0; i<numCourses; i++){
            if(!dfs(edges,i,vis)){
                return new int []{} ;
            }
        }
        int [] arr = new int [res.size()] ;
        int j = 0 ;
        for(int i=0; i<arr.length; i++){
            arr[j++] = res.get(arr.length-i-1) ;
        }
        return arr;
    }
    public boolean dfs(List<List<Integer>> edges, int i, int [] vis){
        if(vis[i]==1){
            return false ;
        }
        if(vis[i]==-1){
            return true ;
        }
        vis[i] = 1 ;
      
        for(int j : edges.get(i)){
            if(!dfs(edges,j,vis)){
                return false ;
            }
        }
        vis[i] = -1 ;
         res.add(i) ;
        return true ;
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nuist__NJUPT

给个鼓励吧,谢谢你

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值