被围困的陆地单元格问题 | 豆包MarsCode AI刷题

122 阅读4分钟

题目描述

小R正在处理一个 m x n 大小的二进制矩阵 grid,其中 0 表示海洋单元格,1 表示陆地单元格。一个移动是指从一个陆地单元格走到相邻的另一个陆地单元格,或者跨过网格的边界。小R想知道有多少陆地单元格无法通过任意次数的移动离开网格的边界。也就是说,找出所有被海洋或边界包围的陆地单元格。

思路

  1. 初始化:创建一个与 grid 大小相同的 visited 矩阵,用于记录哪些单元格已经被访问过。
  2. 标记边界可达的陆地:从所有边界上的陆地单元格开始,使用深度优先搜索(DFS)或广度优先搜索(BFS)标记所有可以从边界到达的陆地单元格。
  3. 统计被包围的陆地:遍历整个 grid,统计未被标记的陆地单元格的数量。

图解

假设我们有一个 4x4 的 grid 如下:

0 0 0 0
1 0 1 0
0 1 1 0
0 0 0 0
  1. 初始化

    • 创建一个 4x4 的 visited 矩阵,初始值为 False
  2. 标记边界可达的陆地

    • 从边界上的陆地单元格开始标记:

      • (1, 0) -> (1, 2)
      • (2, 1) -> (2, 2)
  3. 统计被包围的陆地

    • 遍历整个 grid,统计未被标记的陆地单元格:

      • (1, 2) 和 (2, 1) 已经被标记,不需要统计。
      • (2, 2) 未被标记,计数器加1。

最终结果为3。

代码详解

python

def solution(grid: list) -> int:
    if not grid or not grid[0]:
        return 0
    
    m, n = len(grid), len(grid[0])
    
    # 验证输入矩阵中的每个元素是否为0或1
    for row in grid:
        for cell in row:
            if cell not in [0, 1]:
                return 0
    
    visited = [[False] * n for _ in range(m)]
    
    def dfs(x, y):
        if x < 0 or x >= m or y < 0 or y >= n or grid[x][y] == 0 or visited[x][y]:
            return
        visited[x][y] = True
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        for dx, dy in directions:
            dfs(x + dx, y + dy)
    
    # 标记所有从边界可达的陆地
    for i in range(m):
        for j in [0, n - 1]:
            if grid[i][j] == 1 and not visited[i][j]:
                dfs(i, j)
    
    for j in range(n):
        for i in [0, m - 1]:
            if grid[i][j] == 1 and not visited[i][j]:
                dfs(i, j)
    
    # 统计被包围的陆地
    count = 0
    for i in range(m):
        for j in range(n):
            if grid[i][j] == 1 and not visited[i][j]:
                count += 1
    
    return count

知识总结

  1. 深度优先搜索(DFS) :DFS 是一种常用的图遍历算法,适用于解决连通性问题。通过递归或栈实现,可以标记所有从起点可达的节点。
  2. 二维矩阵的遍历:处理二维矩阵时,常用的方法是使用嵌套循环遍历每个元素。对于边界处理,可以单独处理四条边。
  3. 输入验证:在处理输入数据时,确保数据符合预期是非常重要的。可以通过简单的条件判断来验证输入的有效性。
  4. 布尔矩阵:使用布尔矩阵 visited 来记录已经访问过的节点,避免重复访问和死循环。

学习建议

  1. 理解算法:在编写代码前,先理解算法的基本思想和步骤。可以通过画图或手动模拟来帮助理解。
  2. 调试技巧:遇到问题时,可以通过打印中间结果或使用调试工具来逐步排查问题。
  3. 代码优化:在确保功能正确的基础上,可以尝试优化代码,提高效率。例如,可以使用集合或字典来替代列表,减少查找时间。
  4. 多做练习:多做一些类似的题目,巩固对算法的理解和应用能力。可以参考题解和讨论区,学习不同的解题思路。

问题总结和解决方法

  1. 输入验证问题

    • 问题:测试用例中包含非0和非1的值,导致代码输出错误。
    • 解决方法:在处理输入前,先验证矩阵中的每个元素是否为0或1。如果不满足条件,直接返回0。
  2. 边界处理问题

    • 问题:边界上的陆地单元格没有正确标记,导致统计结果错误。
    • 解决方法:分别处理四条边界,确保所有边界上的陆地单元格都被标记。
  3. DFS 递归问题

    • 问题:DFS 递归深度过大,可能导致栈溢出。
    • 解决方法:可以使用迭代方式实现 DFS,使用栈来模拟递归过程。

通过这次刷题,我深刻体会到了输入验证和边界处理的重要性。同时,也学会了如何使用布尔矩阵来记录访问状态,避免重复访问。希望这些经验和建议对其他同学有所帮助。