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

Posted nuist__NJUPT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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-图像渲染
题目链接:题目链接戳这里!!!以上是关于leetcode之深度优先搜索刷题总结2的主要内容,如果未能解决你的问题,请参考以下文章

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

LeetCode刷题之搜索(Java)

LeetCode刷题之搜索(Java)

leetcode之动态规划刷题总结2

leetcode 79. Word Search 单词搜索

面试刷题:深度优先搜索DFS | 第87期