题目描述
小R正在处理一个 m x n 大小的二进制矩阵 grid,其中 0 表示海洋单元格,1 表示陆地单元格。一个移动是指从一个陆地单元格走到相邻的另一个陆地单元格,或者跨过网格的边界。小R想知道有多少陆地单元格无法通过任意次数的移动离开网格的边界。也就是说,找出所有被海洋或边界包围的陆地单元格。
思路
- 初始化:创建一个与
grid大小相同的visited矩阵,用于记录哪些单元格已经被访问过。 - 标记边界可达的陆地:从所有边界上的陆地单元格开始,使用深度优先搜索(DFS)或广度优先搜索(BFS)标记所有可以从边界到达的陆地单元格。
- 统计被包围的陆地:遍历整个
grid,统计未被标记的陆地单元格的数量。
图解
假设我们有一个 4x4 的 grid 如下:
0 0 0 0
1 0 1 0
0 1 1 0
0 0 0 0
-
初始化:
- 创建一个 4x4 的
visited矩阵,初始值为False。
- 创建一个 4x4 的
-
标记边界可达的陆地:
-
从边界上的陆地单元格开始标记:
- (1, 0) -> (1, 2)
- (2, 1) -> (2, 2)
-
-
统计被包围的陆地:
-
遍历整个
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
知识总结
- 深度优先搜索(DFS) :DFS 是一种常用的图遍历算法,适用于解决连通性问题。通过递归或栈实现,可以标记所有从起点可达的节点。
- 二维矩阵的遍历:处理二维矩阵时,常用的方法是使用嵌套循环遍历每个元素。对于边界处理,可以单独处理四条边。
- 输入验证:在处理输入数据时,确保数据符合预期是非常重要的。可以通过简单的条件判断来验证输入的有效性。
- 布尔矩阵:使用布尔矩阵
visited来记录已经访问过的节点,避免重复访问和死循环。
学习建议
- 理解算法:在编写代码前,先理解算法的基本思想和步骤。可以通过画图或手动模拟来帮助理解。
- 调试技巧:遇到问题时,可以通过打印中间结果或使用调试工具来逐步排查问题。
- 代码优化:在确保功能正确的基础上,可以尝试优化代码,提高效率。例如,可以使用集合或字典来替代列表,减少查找时间。
- 多做练习:多做一些类似的题目,巩固对算法的理解和应用能力。可以参考题解和讨论区,学习不同的解题思路。
问题总结和解决方法
-
输入验证问题:
- 问题:测试用例中包含非0和非1的值,导致代码输出错误。
- 解决方法:在处理输入前,先验证矩阵中的每个元素是否为0或1。如果不满足条件,直接返回0。
-
边界处理问题:
- 问题:边界上的陆地单元格没有正确标记,导致统计结果错误。
- 解决方法:分别处理四条边界,确保所有边界上的陆地单元格都被标记。
-
DFS 递归问题:
- 问题:DFS 递归深度过大,可能导致栈溢出。
- 解决方法:可以使用迭代方式实现 DFS,使用栈来模拟递归过程。
通过这次刷题,我深刻体会到了输入验证和边界处理的重要性。同时,也学会了如何使用布尔矩阵来记录访问状态,避免重复访问。希望这些经验和建议对其他同学有所帮助。