[LeetCode] DFS template second kill question

1. DFS basic framework

DFS in Figure

The core issue is "Traversing a two-dimensional array"
The two-dimensional array traversal framework is as follows:

void dfs (int[][] grid , int i , int j , boolean[] visited) {
    int m = gird.length , n = grid[0].length;
    //Check for out of bounds
    if (i < 0 || j < 0 || i >= m || j >= n) {
        //Index boundary exceeded
        return ;
    }
    //Check whether the node has been accessed or exclude irrelevant nodes in the topic
    if (visited[i][j] || grid[i][j] != ...  ) {
        return ;
    }
    //access node 
    visited[i][j] = true;
    //"Infection"
    grid[i][j] = ... ;
    dfs(grid,i+1,j,visited); //upper
    dfs(grid,i-1,j,visited); //lower
    dfs(grid,i,j-1,visited); //Left
    dfs(grid,i,j+1,visited); //right
}   

//Small tips: you can use "direction array" to traverse up, down, left and right
    int[][] dirs = new int[][]{ {-1,0} , {1,0} , {0,-1} , {0,1} };
    //Recursive traversal of upper, lower, left and right nodes
    for (int[] d : dirs) {
        int next_i = i + d[0];
        int next_j = j + d[1];
        dfs(grid , next_i , next_j , visited);
    }

DFS in tree

Compared with the figure, it is much simpler and does not need to judge whether to access repeatedly

int dfs (TreeNode root , ...) {
    
    //Check whether the end is reached
    if (root == null) {
        return ...;
    }
    //Check some special situations of left and right children
    if (root.left ... && root.right ...  ) {
        return ...;
    }
    //access node 
    Update related variables
    //"Infection" can be transmitted to left and right children
    return  ...
    		dfs(root.left,...);
    		dfs(root.right,...
}   

2. LeetCode related examples

(1) Flood Fill algorithm (island problem)

LC 733 image rendering (paint bucket tool)

LeetCode 733 The function to be realized is similar to the "paint bucket tool" in PS
Just follow the template directly

class Solution {
    public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
        //If the color to be adjusted does not change, return directly
        if(image[sr][sc]==newColor) 
            return image;
        dfs(image,sr,sc,image[sr][sc],newColor);
        return image;
    }
    
    //dfs
    public void dfs(int[][] image,int x,int y,int oldColor,int newColor){
          //Coordinate out of bounds and different colors
        if(x<0 || x>=image.length || y<0 || y>=image[0].length || image[x][y]!=oldColor){
            return ;
        }
        image[x][y] = newColor;  //Coloring
        dfs(image,x+1,y,oldColor,newColor);
        dfs(image,x-1,y,oldColor,newColor);
        dfs(image,x,y+1,oldColor,newColor);
        dfs(image,x,y-1,oldColor,newColor);
    }
}

LC 200 number of islands

LeetCode 200

It can be associated with "dyeing". That is to dye a certain block (an island), and the question is how many blocks (islands)? What is the role of DFS in this question?
It is still "staining", but to be precise, it is "flooding the island" to avoid repeated counting
First traversing search, find a region for 1 (land) count +1, and then call DFS to submerge the island.

class Solution {
    public int numIslands(char[][] grid) {
        int res = 0; //Number of islands
        for (int i = 0; i < grid.length;i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == '1') { //Found one
                    res++;
                    dfs(grid,i,j); //Flooded the island
                }
            }
        }
        return res;
    }

    //Flooded the island with dfs
    public void dfs (char[][] grid , int i , int j) {
        //Detect whether it is out of bounds
        if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length)
            return;
        //Is the island detected
        if (grid[i][j] != '1')
            return;
        //flooded 
        grid[i][j] = '0';
        dfs(grid , i+1 , j);
        dfs(grid , i-1 , j);
        dfs(grid , i , j+1);
        dfs(grid , i , j-1);
    }
}

Maximum area of LC 695 Island

LeetCode 695

Similar to the previous question
It's just to ask for the area when the island is flooded

class Solution {
    public int maxAreaOfIsland(int[][] grid) {
        int res = 0;  //Record maximum area
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1) {
                    res = Math.max(res,dfs(grid,i,j));
                }
            }
        }
        return res;
    }

    //Flood the island while returning to the area of the island
    public int dfs (int[][] grid , int i, int j) {
        //Detection boundary value
        if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length) 
            return 0;
        //Out of the boundary of the island
        if (grid[i][j] == 0)
            return 0;
        //flooded 
        grid[i][j] = 0;

        return dfs(grid,i-1,j)
             + dfs(grid,i+1,j)
             + dfs(grid,i,j+1)
             + dfs(grid,i,j-1) + 1;
    }
}

Number of LC 1020 enclaves

LeetCode 1020
The essence is to seek a "closed island", which requires a "real island" surrounded by water
That is to flood the islands around (up, down, left and right), and then count the rest

//Flooded the surrounding
        for (int j = 0; j < grid[0].length; j++) {
            dfs(grid,0,j);  //Submerged upper
            dfs(grid,grid.length-1,j); //Submerged
        }
        for (int i = 0; i < grid.length; i++) {
            dfs(grid,i,0);   //On the left
            dfs(grid,i,grid[0].length-1); //On the right
        }

After that, it will operate normally. If the number of "closed islands" is required, the islands will be flooded one by one
If the area of "closed island" is required, the size of the island shall be compared while flooding the island
In this problem, the total area of all "closed islands" is calculated, so there is no need to flood the island, and you can traverse it directly

The complete code is as follows:

class Solution {
    public int numEnclaves(int[][] grid) {
        int res = 0;
        //Flood the islands on four sides first
        for (int j = 0; j < grid[0].length; j++) {
            dfs(grid,0,j);  //Submerged upper
            dfs(grid,grid.length-1,j); //Submerged
        }
        for (int i = 0; i < grid.length; i++) {
            dfs(grid,i,0);   //On the left
            dfs(grid,i,grid[0].length-1); //On the right
        }

        //Count the number of remaining islands
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == 1) {
                    res++;
                    //dfs(grid,i,j);
                }
            }
        }
        return res;
    }

    public void dfs(int[][] grid, int i, int j) {
        //Detect whether it is out of bounds
        if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length) 
            return;
        //Boundary detected
        if (grid[i][j] == 0)
            return;
        //Flooded Island
        grid[i][j] = 0;
        dfs(grid,i+1,j);
        dfs(grid,i-1,j);
        dfs(grid,i,j+1);
        dfs(grid,i,j-1);
    }
}

LC 1034 boundary coloring

LeetCode 1034

First understand the meaning of the question:
Connected component: refers to the collection of grids (i.e. adjacent grids) with the same color in one of the four directions up, down, left and right
Boundary coloring: the grid next to other colors or the grid next to the matrix boundary in the connected components pointed to by the coordinates of row and col is called boundary, and these boundaries are colored.

Consistent with the idea of DFS inundating islands:
The connected component is equivalent to an island
Coloring the connected component is equivalent to flooding the island (the problem requires coloring the boundary of the connected component)

 Basic ideas:
The same is the idea of drowning the island 
(1) First, color the connected components as a whole
(2) traverse again ,Restore the internal elements to the original color to achieve the effect of boundary coloring

How to determine whether it is an internal element?
The surrounding elements have been visited
if (visited[i][j] && visited[i+1][j] && visited[i-1][j] && visited[i][j-1] && visited[i][j+1]) {...}
class Solution {
public:
    vector<vector<int>> colorBorder(vector<vector<int>>& grid, int row, int col, int color) {
        if (grid[row][col] == color)
            return grid;

        int oldColor = grid[row][col];
        vector<vector<bool>> visited(grid.size(),vector(grid[0].size(),false));
        dfs(grid,row,col,oldColor,color,visited); //Find the connected component first
        //Find the boundary value in the connected component
        for (int i = 1; i < grid.size() - 1; i++) {
            for (int j = 1; j < grid[0].size() - 1; j++) {
                // Look for the inner point and dye the inner point back
                if (visited[i][j] && visited[i+1][j] && visited[i-1][j] && visited[i][j-1] && visited[i][j+1]) {
                    grid[i][j] = oldColor;
                }
            }
        }
        return grid;
    }

    //Basic idea: 
    //First round: dfs is similar to the island flooding the connected component
    //The second round: traverse again, find the internal points and dye them back
    void dfs(vector<vector<int>>& grid , int i , int j , int oldColor , int newColor,vector<vector<bool>>& visited) {
        //Boundary value judgment
        if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size())
            return ;
        //Judge whether it has reached the boundary
        if (grid[i][j] != oldColor)
            return ;
        //Finding "rules of connected components" in four directions
        visited[i][j] = true; //Mark the flooded connected component
        grid[i][j] = newColor;
        dfs(grid,i+1,j,oldColor,newColor,visited);
        dfs(grid,i-1,j,oldColor,newColor,visited);
        dfs(grid,i,j+1,oldColor,newColor,visited);
        dfs(grid,i,j-1,oldColor,newColor,visited);
    }
};

(2) Search application

Motion range of the Offer 13 robot

Sword finger Offer 13

class Solution {
    public int movingCount(int m, int n, int k) {
        boolean[][] visited = new boolean[m][n];
        return dfs(0,0,m,n,k,visited);
    }

    public int dfs(int i,int j,int m,int n,int k,boolean[][] visited) {
        //Hyperboundary
        if (i < 0 || i >= m || j < 0 || j >= n) {
            return 0;
        }
        //Over k and visited (prevent turning back)
        if (i%10 + i/10 + j/10 + j%10 > k || visited[i][j]) {
            return 0;
        }
        //sign
        visited[i][j] = true;
        //Spread to surrounding nodes
        return 1+dfs(i+1,j,m,n,k,visited)
                +dfs(i-1,j,m,n,k,visited)
                +dfs(i,j+1,m,n,k,visited)
                +dfs(i,j-1,m,n,k,visited);
    }
}

LC 1306 jumping game III

LeetCode 1306

// There are only two types of start + arr [start] start arr [start] for each outward diffusion

class Solution {
    public boolean canReach(int[] arr, int start) {
        boolean[] visited = new boolean[arr.length];
        return dfs(arr,start,visited);
    }
    public boolean dfs(int[] arr, int start,boolean[] visited) {
        //Cross border and visited (avoid going back)
        if (start < 0 || start >= arr.length || visited[start]) {
            return false;
        }
        int step = arr[start];
        //Mark it
        visited[start] = true;
        //Successful arrival
        if (step == 0) {
            return true;
        }
        return dfs(arr,start+step,visited) || dfs(arr,start - step,visited);
    }
}

(3) Binary tree related DFS

LC112 path sum

LeetCode 112

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        return dfs(root,targetSum);
    }

    public boolean dfs (TreeNode root , int targetSum) {
        if (root == null) {
            return false;
        }
        
        if (root.left == null && root.right == null) {
            return root.val == targetSum;
        }

        return dfs(root.left , targetSum - root.val)
            || dfs(root.right , targetSum - root.val);
    }
}

LC129 find the sum of numbers from root node to leaf node

LeetCode 129

class Solution {
    public int sumNumbers(TreeNode root) {
        return dfs(root , 0);
    }

    int dfs (TreeNode root , int sum) {
        if (root == null) 
            return 0;
        if (root.left == null && root.right == null)
            return sum + root.val;
        sum += root.val;
        return dfs(root.left , 10*sum)
             + dfs(root.right , 10*sum);       
    }
}

Keywords: Java Algorithm leetcode

Added by dimkasmir on Wed, 22 Dec 2021 10:30:40 +0200