二刷Leetcode记录贴-Day1||岛屿问题(待补充)

56 阅读3分钟

Leetcode 200 邻接岛屿

看到题解总结的不错,给出了岛屿问题的主要变形和基本模板。总结如下:

题解链接:leetcode.cn/problems/nu…

过程:本质是对DFS的理解

  1. 二叉树的dfs两个要素:标记相邻节点和判断base case

第一个要素是访问相邻节点。二叉树的相邻节点非常简单,只有左子结点和右子结点两个。二叉树本身就是一个递归定义的结构:一棵二叉树,它的左子树和右子树也是一棵二叉树。那么我们的 DFS 遍历只需要递归调用左子树和右子树即可。

第二个要素是 判断 base case。一般来说,二叉树遍历的 base case 是 root == null。这样一个条件判断其实有两个含义:一方面,这表示 root 指向的子树为空,不需要再往下遍历了。另一方面,在 root == null 的时候及时返回,可以让后面的 root.left 和 root.right 操作不会出现空指针异常。

岛屿问题通解:

void dfs(int[][] grid, int r, int c) { 
    // 判断 base case 
    if (!inArea(grid, r, c)) { 
        return; 
    } 
    // 如果这个格子不是岛屿,直接返回 
    if (grid[r][c] != 1) { 
        return; 
    } 
    grid[r][c] = 2; // 将格子标记为「已遍历过」 
    // 访问上、下、左、右四个相邻结点 
    dfs(grid, r - 1, c); 
    dfs(grid, r + 1, c); 
    dfs(grid, r, c - 1); 
    dfs(grid, r, c + 1); 
    } 
    // 判断坐标 (r, c) 是否在网格中 
    boolean inArea(int[][] grid, int r, int c) { 
        return 0 <= r && r < grid.length && 0 <= c && c < grid[0].length; 
    } 

Python实现

    def numIslands(self, grid: List[List[str]]) -> int:
        res = 0
        if not grid:return 0
        def dfs(i,j):
            if i<0 or i>=len(grid) or j<0 or j>=len(grid[0]) or grid[i][j] != "1":
                return
            grid[i][j] = "0"
            dfs(i-1,j)
            dfs(i+1,j)
            dfs(i,j-1)
            dfs(i,j+1)
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == "1":
                    dfs(i,j)
                    res += 1
        return res

C++实现 (注意.size()用法)

public:
    void dfs(vector<vector<char>>& grid, int r, int c){
        //base case
        if(!inArea(grid, r, c)){
            return;
        }
        //如果非岛屿,直接返回
        if (grid[r][c] != '1'){
            return;
        }
        grid[r][c] = '2';//标记已遍历格子

        //访问节点
        dfs(grid, r - 1, c);
        dfs(grid, r + 1, c);
        dfs(grid, r, c - 1);
        dfs(grid, r, c + 1);
    }

    bool inArea(vector<vector<char>>& grid, int r, int c){
        return 0 <= r && r < grid.size() && 0 <= c && c < grid[0].size();
    }
    int numIslands(vector<vector<char>>& grid) {
        int res = 0;
        for (int i = 0; i<grid.size();i++){
            for (int j = 0;j<grid[0].size();j++){
                if(grid[i][j] == '1'){
                    dfs(grid,i,j);
                    res++;
                }
            }
        }
        return res;
    }
};

相关例题:

Leetcode 695岛屿最大面积 ( area计数型+ int标识)

C++实现:

public:
    int area(vector<vector<int>>& grid, int r, int c){
        //base case
        if(!inArea(grid, r, c)){
            return 0;
        }
        //如果非岛屿,直接返回
        if (grid[r][c] != 1){
            return 0;
        }
        grid[r][c] = 2;//标记已遍历格子

        //访问节点
        return 1
            + area(grid, r - 1, c)
            + area(grid, r + 1, c)
            + area(grid, r, c - 1)
            + area(grid, r, c + 1);
    }

    bool inArea(vector<vector<int>>& grid, int r, int c){
        return 0 <= r && r < grid.size() && 0 <= c && c < grid[0].size();
    }
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int res = 0;
        for (int i = 0; i<grid.size();i++){
            for (int j = 0;j<grid[0].size();j++){
                if(grid[i][j] == 1){
                    int a = area(grid,i,j);
                    res = std::max(res, a);
                }
            }
        }
        return res;
    }
};

Leetcode 463 岛屿周长(边界对应dfs边界, 黄边+蓝边)

C++版本:

public:
    int islandPerimeter(vector<vector<int>>& grid) {
    for (int r = 0; r < grid.size(); r++) {
        for (int c = 0; c < grid[0].size(); c++) {
            if (grid[r][c] == 1) {
                // 题目限制只有一个岛屿,计算一个即可
                return dfs(grid, r, c);
            }
        }
    }
    return 0;
    }
    int dfs(vector<vector<int>>& grid, int r, int c) {
    // 函数因为「坐标 (r, c) 超出网格范围」返回,对应一条黄色的边
    if (!inArea(grid, r, c)) {
        return 1;
    }
    // 函数因为「当前格子是海洋格子」返回,对应一条蓝色的边
    if (grid[r][c] == 0) {
        return 1;
    }
    // 函数因为「当前格子是已遍历的陆地格子」返回,和周长没关系
    if (grid[r][c] != 1) {
        return 0;
    }
    grid[r][c] = 2;
    return dfs(grid, r - 1, c)
        + dfs(grid, r + 1, c)
        + dfs(grid, r, c - 1)
        + dfs(grid, r, c + 1);
}

// 判断坐标 (r, c) 是否在网格中
    bool inArea(vector<vector<int>>& grid, int r, int c) {
        return 0 <= r && r < grid.size() && 0 <= c && c < grid[0].size();
}
};