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

191 阅读5分钟

被围困的陆地单元格问题

问题描述

小R正在处理一个 m x n 大小的二进制矩阵 grid,其中 0 表示海洋单元格,1 表示陆地单元格。一个移动是指从一个陆地单元格走到相邻的另一个陆地单元格,或者跨过网格的边界。

小R想知道有多少陆地单元格无法通过任意次数的移动离开网格的边界。也就是说,找出所有被海洋或边界包围的陆地单元格。

分析

不妨找出能够离开网络边界的陆地单元格,则不能离开的陆地单元格数目即为陆地单元格总数减去能够离开的数目。要找出能够离开的单元格数,对矩阵最外围是陆地的所有地块进行搜索,将相连的地块进行不重计数。

代码

这里将矩阵外围围了一圈陆地方便计数。

def solution(grid: list) -> int:
    m, n = len(grid), len(grid[0])
    newGrid = [[1 for _ in range(n + 2)] for _ in range(m + 2)]
    tot = 2 * (m + n) + 4
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            newGrid[i][j] = grid[i - 1][j - 1]
            if newGrid[i][j] != 0: tot += 1
    grid = newGrid
    m, n = len(grid), len(grid[0])
    visit = [[False for _ in range(n)] for _ in range(m)]
    def dfs(x: int, y: int) -> None:
        if x < 0 or x >= m or y < 0 or y >= n or visit[x][y] or grid[x][y] == 0: return
        visit[x][y] = True
        dfs(x, y + 1)
        dfs(x, y - 1)
        dfs(x + 1, y)
        dfs(x - 1, y)
    dfs(0, 0)
    return tot - sum(sum(item) for item in visit)

AI代码解析

这段代码实现了一个计算网格中“岛屿”的周长的功能。具体来说,它通过深度优先搜索(DFS)算法来遍历网格中的每个单元格,并计算所有被访问到的单元格的总和。以下是对代码的详细解释:

  1. 初始化

    m, n = len(grid), len(grid[0])
    newGrid = [[1 for _ in range(n + 2)] for _ in range(m + 2)]
    tot = 2 * (m + n) + 4
    
    • mn 分别是原始网格的行数和列数。
    • newGrid 是一个比原网格大一圈的网格,四周用值为1的边界填充。这是为了方便处理边界情况。
    • tot 是初始周长,等于网格的周长加上四个角的周长。
  2. 填充新网格

    for i in range(1, m + 1):
        for j in range(1, n + 1):
            newGrid[i][j] = grid[i - 1][j - 1]
            if newGrid[i][j] != 0: tot += 1
    
    • 将原始网格的值复制到新网格的中心部分。
    • 如果某个单元格的值不为0,则增加总周长。
  3. 更新网格和访问矩阵

    grid = newGrid
    m, n = len(grid), len(grid[0])
    visit = [[False for _ in range(n)] for _ in range(m)]
    
    • 更新网格为新网格。
    • 重新定义网格的大小。
    • 创建一个与新网格大小相同的访问矩阵,用于记录哪些单元格已经被访问过。
  4. 深度优先搜索(DFS)

    def dfs(x: int, y: int) -> None:
        if x < 0 or x >= m or y < 0 or y >= n or visit[x][y] or grid[x][y] == 0: return
        visit[x][y] = True
        dfs(x, y + 1)
        dfs(x, y - 1)
        dfs(x + 1, y)
        dfs(x - 1, y)
    
    • dfs 函数用于递归地访问相邻的单元格。
    • 如果当前单元格越界、已经访问过或者值为0,则返回。
    • 否则,标记当前单元格为已访问,并递归访问其上下左右四个方向的邻居。
  5. 执行DFS并计算结果

    dfs(0, 0)
    return tot - sum(sum(item) for item in visit)
    
    • 从左上角开始执行DFS。
    • 最终结果是初始周长减去被访问到的单元格的数量。

总结起来,这段代码通过扩展网格、使用DFS遍历网格,并计算未被访问到的单元格数量,从而得出了网格中岛屿的周长。

知识点总结

要解决这个问题,我们可以总结以下几个关键的编程知识点:

1. 深度优先搜索(DFS)

  • 概念: DFS 是一种用于遍历或搜索树或图数据结构的算法。它从根节点开始,沿着一条路径尽可能深地探索,直到没有未探索的相邻节点,然后回溯到上一个节点,继续探索其他路径。
  • 应用: 在这个问题中,DFS 用于从边界上的陆地单元格开始,标记所有可以通过移动到达的陆地单元格。

2. 矩阵遍历

  • 概念: 矩阵遍历是指访问矩阵中的每一个元素。通常使用嵌套循环来实现。
  • 应用: 在这个问题中,我们需要遍历整个矩阵来标记陆地单元格,并计算被包围的陆地单元格的数量。

3. 边界条件处理

  • 概念: 边界条件是指在算法或程序中需要特别处理的特殊情况,通常是输入数据的极端情况。
  • 应用: 在这个问题中,我们需要特别处理矩阵的边界,因为边界上的陆地单元格不能被认为是被包围的。

4. 递归

  • 概念: 递归是一种函数调用自身的技术。它通常用于解决可以分解为相似子问题的问题。
  • 应用: 在这个问题中,DFS 的实现通常使用递归来探索所有可能的路径。

5. 二维数组

  • 概念: 二维数组是一个数组的数组,通常用于表示矩阵或表格数据。
  • 应用: 在这个问题中,矩阵 grid 是一个二维数组,表示陆地和海洋的分布。

6. 访问标记

  • 概念: 访问标记是一种用于记录哪些节点已经被访问过的技术,通常用于避免重复访问和无限循环。
  • 应用: 在这个问题中,我们使用一个二维布尔数组 visit 来标记哪些陆地单元格已经被访问过。

7. 复杂度分析

  • 概念: 复杂度分析是评估算法效率的方法,通常包括时间复杂度和空间复杂度。
  • 应用: 在这个问题中,我们需要分析 DFS 的时间复杂度,通常是 O(m * n),其中 m 和 n 分别是矩阵的行数和列数。

通过理解和应用这些知识点,我们可以有效地解决这个问题,并编写出高效的代码。