LeetCode题练习与总结:岛屿数量--200

178 篇文章 0 订阅
113 篇文章 0 订阅

一、题目描述

给你一个由 '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'

二、解题思路

这个问题可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来解决。以下是使用DFS的解题思路:

  1. 遍历整个网格。
  2. 每当遇到一个’1’(陆地),则从这个位置开始进行深度优先搜索,将所有与之相连的’1’都标记为已经访问过(可以将它们标记为’0’,这样就不会再次访问)。
  3. 每进行一次深度优先搜索,就意味着找到了一个岛屿,因此岛屿的数量加一。
  4. 继续遍历网格,直到所有单元格都被访问过。

三、具体代码

class Solution {
    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0) {
            return 0;
        }
        
        int nr = grid.length;
        int nc = grid[0].length;
        int islandCount = 0;
        
        for (int r = 0; r < nr; ++r) {
            for (int c = 0; c < nc; ++c) {
                if (grid[r][c] == '1') {
                    // 发现一个岛屿,进行深度优先搜索
                    dfs(grid, r, c);
                    // 岛屿数量加一
                    islandCount++;
                }
            }
        }
        
        return islandCount;
    }
    
    // 深度优先搜索函数
    private void dfs(char[][] grid, int r, int c) {
        int nr = grid.length;
        int nc = grid[0].length;
        
        // 检查当前位置是否超出边界或者是否为水
        if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') {
            return;
        }
        
        // 标记当前位置为已访问(即把陆地变成水)
        grid[r][c] = '0';
        
        // 继续搜索上下左右四个方向
        dfs(grid, r - 1, c);
        dfs(grid, r + 1, c);
        dfs(grid, r, c - 1);
        dfs(grid, r, c + 1);
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 遍历整个网格:代码中有两个嵌套的for循环,分别遍历网格的行和列。如果网格有m行和n列,那么这两个循环总共执行m * n次。

  • 深度优先搜索(DFS):在每次遇到一个’1’时,会从这个位置开始执行DFS。在最坏的情况下,DFS可能需要遍历整个网格,即每个单元格最多被访问一次。

综合以上两点,整个算法的时间复杂度为O(m * n),因为每个单元格最多只会被访问一次(无论是通过遍历网格还是通过DFS)。

2. 空间复杂度
  • 堆栈空间:由于DFS是递归实现的,所以在递归过程中会消耗堆栈空间。在最坏的情况下,DFS可能需要遍历整个网格,因此堆栈的深度最大可能是m * n

  • 辅助空间:除了递归堆栈外,算法没有使用额外的存储空间。虽然在DFS过程中,我们会修改网格中的值,但这并不算作额外的空间消耗,因为这是在原地进行的。

因此,空间复杂度为O(m * n),这是在最坏情况下递归堆栈的最大深度。

这里m是网格的行数,n是网格的列数。在最坏的情况下,每个单元格都会被访问一次,无论是通过网格遍历还是通过DFS递归。因此,时间复杂度和空间复杂度都是与网格的大小成线性关系的。

五、总结知识点

  1. 类定义class Solution:定义了一个名为Solution的类。

  2. 方法定义public int numIslands(char[][] grid):定义了一个公共方法numIslands,它接受一个二维字符数组grid作为参数,并返回一个整数。

  3. 数组char[][] grid:使用二维字符数组来表示网格。

  4. 条件语句if (grid == null || grid.length == 0):使用if语句来检查输入数组是否为空或长度为零。

  5. 循环结构for循环:使用了两个嵌套的for循环来遍历二维网格的每个元素。

  6. 递归dfs方法:定义了一个递归方法dfs,用于实现深度优先搜索。

  7. 基本数据类型int:用于表示整数类型的变量,例如nrncislandCount

  8. 字符比较grid[r][c] == '1':比较数组中的字符是否等于’1’。

  9. 修改数组元素grid[r][c] = '0':在深度优先搜索中,将已访问的陆地标记为’0’。

  10. 方法调用dfs(grid, r, c):在numIslands方法中调用dfs方法。

  11. 边界检查if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0'):在dfs方法中检查当前坐标是否超出网格边界或是否为水。

  12. 递归终止条件:在dfs方法中,当坐标超出边界或当前单元格为’0’时,递归终止。

  13. 递归调用dfs(grid, r - 1, c); dfs(grid, r + 1, c); dfs(grid, r, c - 1); dfs(grid, r, c + 1);:递归地调用dfs方法来探索四个方向。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一直学习永不止步

谢谢您的鼓励,我会再接再厉的!

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

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

打赏作者

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

抵扣说明:

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

余额充值