LeetCode 200 - 岛屿数量

100 阅读2分钟

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

  示例 1:

输入:grid = [ ["1","1","1","1","0"],
              ["1","1","0","1","0"],
              ["1","1","0","0","0"],
              ["0","0","0","0","0"]
            ]

输出:1

示例 2:

输入:grid = [ ["1","1","0","0","0"],
              ["1","1","0","0","0"],
              ["0","0","1","0","0"],
              ["0","0","0","1","1"]
            ]

输出:3  

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 300
  • grid[i][j] 的值为 '0' 或 '1'

思路:深度优先搜索

为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 1,则以其为起始节点开始进行深度优先搜索。在深度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0。

class Solution {
    public int numIslands(char[][] grid) {
        if(grid == null || grid.length == 0){
            return 0;
        }
        //岛屿数量
        int landNum = 0;
        int rl = grid[0].length;
        int cl = grid.length;

        for(int i = 0;i < cl;i ++){
            for(int j = 0; j< rl;j++){
                //取出所有陆地
                if(grid[i][j] == '1'){
                    landNum ++;
                    dfs(grid,i,j);
                }
            }
        }
        return landNum;
    }

    private void dfs(char[][] grid ,int i,int j){
        int rl = grid[0].length;
        int cl = grid.length;

        //越界返回
        if(i <0 || i >= cl|| j <0 || j >= rl || grid[i][j] == '0'){
            return;
        }

        //已经走过的置为0,避免重复递归
        grid[i][j] = '0';
        //上下左右
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
        dfs(grid, i, j - 1);
        dfs(grid, i, j + 1);
    }
}

复杂度分析

  • 时间复杂度:O(mn),其中 m 和 n 分别为行数和列数。

  • 空间复杂度:O(mn),在最坏情况下,整个网格均为陆地,深度优先搜索的深度达到 mn。

思路:广度优先搜索

为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 1,则将其加入队列,开始进行广度优先搜索。在广度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0。直到队列为空,搜索结束。

class Solution {
    public int numIslands(char[][] grid) {
        if(grid == null || grid.length == 0){
            return 0;
        }
        //岛屿数量
        int landNum = 0;
        int rl = grid[0].length;
        int cl = grid.length;

        for(int i = 0;i < cl;i ++){
            for(int j = 0; j< rl;j++){
                //取出所有陆地
                if(grid[i][j] == '1'){
                    landNum ++;
                    bfs(grid,i,j);
                }
            }
        }
        return landNum;
    }
    private void bfs(char[][] grid, int i, int j){
        Queue<int[]> list = new LinkedList<>();
        list.add(new int[] { i, j });
        while(!list.isEmpty()){
            int[] cur = list.remove();
            i = cur[0]; j = cur[1];
            if(0 <= i && i < grid.length && 0 <= j && j < grid[0].length && grid[i][j] == '1') {
                grid[i][j] = '0';
                list.add(new int[] { i + 1, j });
                list.add(new int[] { i - 1, j });
                list.add(new int[] { i, j + 1 });
                list.add(new int[] { i, j - 1 });
            }
        }
    }
}

复杂度分析

  • 时间复杂度:O(mn),其中 m 和 n 分别为行数和列数。

  • 空间复杂度:O(min(m, n)),在最坏情况下,整个网格均为陆地,队列的大小可以达到 min(m, n)。