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

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

1-课程表
题目链接:题目链接戳这里!!!

思路:将所有的点构成一个有向图,对该图的每个顶点进行搜索,使用vis数组进行标记,如果该顶点为被搜索过,则vis为0,如果被以其他顶点启动的搜索过,则vis为-1,如果被当前顶点为启动点搜索过,vis为1,则说明有环。

AC代码如下:

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<List<Integer>> edge = new ArrayList<>() ;
        for(int i=0; i<numCourses; i++){
            edge.add(new ArrayList<>()) ;
        }
        int [] vis = new int [numCourses] ;
        for(int [] courses : prerequisites){
            edge.get(courses[1]).add(courses[0]) ;
        }

        for(int i=0; i<numCourses; i++){
            if(!dfs(edge,i,vis)){
                return false ;
            }
        }
        return true ;
    }
    public boolean dfs(List<List<Integer>> edge, int i, int []vis){
        if(vis[i]==1){
            return false ;
        }
        if(vis[i]==-1){
            return true ;
        }
        vis[i] = 1 ;
        for(int j : edge.get(i)){
            if(!dfs(edge,j,vis)){
                return false ;
            }
        }
        vis[i] = -1 ;
        return true ;
    }
}

在这里插入图片描述
2-课程表II
题目链接:题目链接戳这里!!!

思路:dfs+栈+有向图

构建有向图,vis数组标记三种状态,vis=0,节点未被访问,vis=1,节点在当前dfs中被访问,vis=-1,节点被之前的dfs所访问,dfs判断每个节点,是否有环,有环则返回空数组,否则需要使用stack记录。

class Solution {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
           List<List<Integer>> edge = new ArrayList<>() ;
           Stack<Integer> stack = new Stack<>() ;
        for(int i=0; i<numCourses; i++){
            edge.add(new ArrayList<>()) ;
        }
        int [] vis = new int [numCourses] ;
        for(int [] courses : prerequisites){
            edge.get(courses[1]).add(courses[0]) ;
        }

        for(int i=0; i<numCourses; i++){
            if(!dfs(edge,i,vis,stack)){
                return new int[]{} ;
            }
        }
       
     
        int [] arr = new int [numCourses] ;
        int k = 0 ;
        
        while(!stack.isEmpty()){
            arr[k] = stack.pop() ;
            k++ ;
        }

        return arr ;
    }
    public boolean dfs(List<List<Integer>> edge, int i, int []vis, Stack<Integer>stack){
        if(vis[i]==1){
            return false ;
        }
        if(vis[i]==-1){
            return true ;
        }
        vis[i] = 1 ;

        for(int j : edge.get(i)){
            if(!dfs(edge,j,vis,stack)){
                return false ;
            }
        }
        vis[i] = -1 ;
        stack.push(i) ;
        return true ;
    }
}

在这里插入图片描述
3-水壶问题
题目链接:题目链接戳这里!!!

思路1:数学法,贝祖定理。

class Solution {
    public boolean canMeasureWater(int jug1Capacity, int jug2Capacity, int targetCapacity) {
        if(jug1Capacity+jug2Capacity<targetCapacity){
            return false ;
        }
        if(jug2Capacity==0 || jug1Capacity==0){
            return targetCapacity==0 || jug2Capacity+jug1Capacity==targetCapacity ;
        }
        return targetCapacity % gcd(jug1Capacity,jug2Capacity) == 0 ;
    }
    public int gcd(int m, int n){
        if(n==0){
            return m  ;
        }
        return gcd(n, m%n) ;
    }

}

在这里插入图片描述
思路2:DFS,用栈模拟

4-字典序排数
题目链接:题目链接戳这里!!!

思路1:用set集合去重和自动排序的功能,当然可以AC,不过效率较低,而且并不是题目要考察的知识点。

class Solution {
    public List<Integer> lexicalOrder(int n) {
        Set<String> set = new TreeSet<>() ;
        List<Integer> list = new ArrayList<>() ;
        for(int i=1; i<=n; i++){
            set.add(String.valueOf(i)) ;
        }
        for(String s : set){
            list.add(Integer.parseInt(s)) ;
        }
        return list ;
    }
}

在这里插入图片描述
思路2:把这些数字看成一个字典树,然后通过dfs进行先序遍历就可以了。

class Solution {
    public List<Integer> lexicalOrder(int n) {
        List<Integer> list = new ArrayList<>() ;
        for(int i=1; i<=9; i++){
            dfs(i,n,list) ;
        }
        return list ;
    }
    public void dfs(int i, int n, List<Integer> list){
        if(i>n){
            return ;
        }
        list.add(i) ;
        for(int j=0; j<=9; j++){
            dfs(i*10+j,n,list) ;
        }
    }
}

在这里插入图片描述
5-岛屿的周长
题目链接:题目链接戳这里!!!

思路1:只要该位置是陆地就沿着四个方向搜索,如果是边界或者是水域则贡献1,如果当前位置已经搜索过,则贡献0.

class Solution {
    int [] offsetX = {1,-1,0,0} ;
    int [] offsetY = {0,0,-1,1} ;
    public int islandPerimeter(int[][] grid) {
        int cnt = 0 ;
        for(int i=0; i<grid.length; i++){
            for(int j=0; j<grid[0].length; j++){
                if(grid[i][j]==1){
                   cnt += dfs(grid,i,j) ;
                }
            }
        }
        return cnt ;
    }
    public int dfs(int [][]grid, int x, int y){
        if(x<0 || y<0 || x>grid.length-1 || y>grid[0].length-1 || grid[x][y]==0){
            return 1 ;
        }
        if(grid[x][y]==2){
            return 0 ;
        }
        grid[x][y] = 2 ;
        int ans = 0 ;
        for(int i=0; i<4; i++){
           int nx = x + offsetX[i] ;
           int ny = y + offsetY[i] ;
            ans += dfs(grid,nx,ny) ; 
        }
        return ans ;

    }
}

在这里插入图片描述
思路2:直接用循环也可以的。如果当前位置是陆地,则当前位置的前后左右四个方向进行判断,如果是边界或者是水域,则当前位置贡献值加1.

class Solution {
    int [] offsetX = {1,-1,0,0} ;
    int [] offsetY = {0,0,-1,1} ;
    public int islandPerimeter(int[][] grid) {
        int ans = 0 ;
       for(int i=0; i<grid.length; i++){
           for(int j=0; j<grid[0].length; j++){
               if(grid[i][j]==1){
                   int cnt = 0 ;
               for(int k=0; k<4; k++){
                   int nx = i + offsetX[k] ;
                   int ny = j + offsetY[k] ;
                 if(nx<0 || ny<0 || nx>grid.length-1 || ny>grid[0].length-1 || grid[nx][ny]==0){
                     cnt ++ ;
               }
               }
               ans += cnt ;
           }
       }
    }
    return ans ;
}
}

在这里插入图片描述
6-甲板上的战舰
题目链接:题目链接戳这里!!!

思路:就是沿着四个方向搜索,判断连通块的数量即可。
每一轮搜索,都把战舰标记为空白,代表搜索过了。

AC代码如下:

class Solution {
    int [] offsetX = {-1,1,0,0} ;
    int [] offsetY = {0,0,-1,1} ;
    public int countBattleships(char[][] board) {
        int cnt = 0 ;
        for(int i=0; i<board.length; i++){
            for(int j=0; j<board[0].length; j++){
                if(board[i][j]=='X'){
                    dfs(board,i,j) ;
                    cnt ++ ;
                }
            }
        }
        return cnt ;
    }
    public void dfs(char[][]board, int x, int y){
        board[x][y] = '.' ;
        for(int i=0; i<4; i++){
            int tx = x + offsetX[i] ;
            int ty = y + offsetY[i] ;
            if(tx<0 || ty<0 || tx>board.length-1 || ty>board[0].length-1){
                continue ;
            }
            if(board[tx][ty]=='X'){
                dfs(board,tx,ty) ;
            }
        }
    }
}

在这里插入图片描述
7-数组嵌套
题目链接:题目链接戳这里!!!

思路:每一次只要当前值不等于Integer.MAX_VALUE,则循环让下一个下标等于当前值,同时计数加1,同时将Integer.MAX_VALUE赋值给当前值,每轮循环找出最大值即可。

AC代码如下:

class Solution {
    public int arrayNesting(int[] nums) {
        int ans = 0 ;
        for(int i=0; i<nums.length; i++){
            if(nums[i]!=Integer.MAX_VALUE){
                int cnt = 0, start = i ;
                while(nums[start]!=Integer.MAX_VALUE){
                    int temp = start ;
                    start = nums[start] ;
                    cnt ++ ;
                    nums[temp] = Integer.MAX_VALUE ;
                }
                ans = Math.max(ans, cnt) ;
            }
        }
        return ans ;
    }
}

在这里插入图片描述
8-图像渲染
题目链接:题目链接戳这里!!!

思路:如果当前要修改的位置颜色与newColor相同,则不需要修改,否则,将所有与当前位置联通的都修改为新颜色。

class Solution {
    int [] dx = {-1,1,0,0} ;
    int [] dy = {0,0,-1,1} ;
    public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
        if(image[sr][sc]==newColor){
            return image ;
        }
        int n = image[sr][sc] ;
        dfs(image,sr,sc,n,newColor) ;
  
        return image ;
    }
    public void dfs(int [][]image, int x, int y, int n, int newColor){
        image[x][y] = newColor ;
        for(int i=0; i<4; i++){
           int tx = x + dx[i] ;
           int ty = y + dy[i] ;
            if(tx<0 || ty<0 || tx>image.length-1 || ty>image[0].length-1){
                continue ;
            }
            if(image[tx][ty]==n){
                dfs(image,tx,ty,n,newColor) ;
            }
        }
    }
}

在这里插入图片描述
9-钥匙和房间
题目链接:题目链接戳这里!!!

思路:初始化所有房间为false,即未被访问,dfs搜索每个房间,并已该房间的钥匙为房间号继续搜索,如果出现重复搜索则终止当前搜索,直至搜索完成,判断是否所有房间都被标记为true即可。

class Solution {
    public boolean canVisitAllRooms(List<List<Integer>> rooms) {
        List<Boolean> vis = new ArrayList<>() ;
        for(int i=0; i<rooms.size(); i++){
            vis.add(false) ;
        }
        dfs(rooms,vis,0) ;
        for(boolean res : vis){
            if(res==false){
                return false ;
            }
        }
        return true ;
    }
    public void dfs(List<List<Integer>> rooms, List<Boolean> vis, int i){
        if(vis.get(i)){
            return ;
        }
        vis.set(i, true) ;
        for(Integer j : rooms.get(i)){
            dfs(rooms,vis,j) ;
        }
    }
}

在这里插入图片描述
10-边界着色
题目链接:题目链接戳这里!!!

思路:就是dfs判断联通块,如果联通则确当是否是边界,边界则染色,注意搜索过的不能再次搜索。

另外边界的判断有两种,一种是第一行/第一列/最后一行/最后一列;另一种则是判断当前的值与原始数组的同样位置的上下左右对比,如果有一个不一样的,也认为是边界。

class Solution {
    int [] dx = {-1,1,0,0} ;
    int [] dy = {0,0,-1,1} ;
    public int[][] colorBorder(int[][] grid, int row, int col, int color) {
        int n = grid[row][col] ;
        if(n==color){
            return grid ;
        }
        boolean [][]vis = new boolean[grid.length][grid[0].length] ;
        int [][] temp = new int[grid.length][grid[0].length] ;
        for(int i=0; i<grid.length; i++){
            for(int j=0; j<grid[0].length; j++){
                temp[i][j] = grid[i][j] ;
            }
        }
        vis[row][col] = true ;
        dfs(grid,row,col,n,color,vis,temp) ;

        return grid ;
    }
    public void dfs(int [][]grid, int row, int col, int n, int color, boolean [][]vis, int [][] temp){
      
        if(row==0 || col==0 || row==grid.length-1 || col==grid[0].length-1){
            grid[row][col] = color ;
        }else if(temp[row][col-1]!=n ||temp[row][col+1]!=n || temp[row+1][col]!=n || temp[row-1][col]!=n){
            grid[row][col] = color ;
        }
    
        for(int i=0; i<4; i++){
            int tx = row + dx[i] ;
            int ty = col + dy[i] ;
        if(tx<0 || ty<0 || tx>grid.length-1 || ty>grid[0].length-1){
            continue ;
        }else if(!vis[tx][ty] && grid[tx][ty]==n){
            vis[tx][ty] = true ;
            dfs(grid,tx,ty,n,color,vis,temp) ;
            }
        }
    }
}

在这里插入图片描述
志存高远,责任为先,加油吧,少年!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

nuist__NJUPT

给个鼓励吧,谢谢你

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

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

打赏作者

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

抵扣说明:

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

余额充值