

文章目录
摘要
这道题乍一看是个"地图题",很多人第一反应可能是 DFS / BFS,甚至想去模拟整条边界走一圈。但其实这是一道非常典型的"把问题拆小"的题。
你根本不需要真的去"绕岛一周",只要站在每一块陆地的角度,问一句话就够了:
我这块地,有几条边是暴露在水里的?
把这个问题想清楚,代码会非常简单,而且几乎不可能写错。

描述
题目给你一个二维网格 grid:
1表示陆地0表示水域
已知条件非常友好:
- 整个地图被水包围
- 只有一个岛屿
- 岛屿内部没有湖(也就是说,水不会被陆地完全包住)
- 相邻只考虑 上下左右,不考虑对角线
每一个格子都是边长为 1 的正方形,你需要计算:
这个岛屿的 总周长
题解答案
这道题最清晰、最不容易出 bug 的解法可以用一句话概括:
每一块陆地默认贡献 4 条边,每和另一块陆地相邻一次,就少 1 条边。
换句话说:
-
遍历整个网格
-
遇到一块陆地
- 先加 4
- 看它的上下左右
- 每发现一个相邻的陆地,就减 1
最后所有陆地的贡献加起来,就是岛屿的周长。
题解代码分析
为什么每块陆地是 4 条边?
这个很直观:
- 一个正方形,本来就是 4 条边
- 如果它四周全是水,那这 4 条边全都算周长
为什么相邻就要减边?
当两块陆地挨在一起时,比如左右相邻:
[1][1]
它们中间那条边,其实是"内部边",不属于周长。
而且要注意一个细节:
- 对于当前这块地来说
- 只要有一个方向是陆地
- 那个方向就不能算周长
所以:
- 每发现一个相邻陆地
- 当前格子的周长贡献就要
-1
这样会不会重复计算?
不会。
因为我们是站在每一块陆地的角度算自己的边 ,不是在算"边本身"。
每一条真正的外边,只会被某一块陆地算一次。

Swift 可运行 Demo 代码
swift
import Foundation
class Solution {
func islandPerimeter(_ grid: [[Int]]) -> Int {
let rows = grid.count
let cols = grid[0].count
var perimeter = 0
for i in 0..<rows {
for j in 0..<cols {
if grid[i][j] == 1 {
// 每块陆地默认 4 条边
perimeter += 4
// 上
if i > 0 && grid[i - 1][j] == 1 {
perimeter -= 1
}
// 下
if i < rows - 1 && grid[i + 1][j] == 1 {
perimeter -= 1
}
// 左
if j > 0 && grid[i][j - 1] == 1 {
perimeter -= 1
}
// 右
if j < cols - 1 && grid[i][j + 1] == 1 {
perimeter -= 1
}
}
}
}
return perimeter
}
}
代码逐步解析
swift
if grid[i][j] == 1 {
perimeter += 4
}
只要是陆地,先把 4 条边加上,这是"理论最大值"。
swift
if i > 0 && grid[i - 1][j] == 1 {
perimeter -= 1
}
检查上方是否是陆地:
- 如果是,说明上边不是周长
- 减 1
上下左右四个方向完全一样的逻辑。
为什么不担心越界?
每次检查前都先判断:
i > 0i < rows - 1j > 0j < cols - 1
这也是写网格题时非常重要的一个习惯。
示例测试及结果
swift
let solution = Solution()
let grid1 = [
[0,1,0,0],
[1,1,1,0],
[0,1,0,0],
[1,1,0,0]
]
print(solution.islandPerimeter(grid1)) // 16
let grid2 = [[1]]
print(solution.islandPerimeter(grid2)) // 4
let grid3 = [[1,0]]
print(solution.islandPerimeter(grid3)) // 4
输出结果:
16
4
4
和题目给出的示例完全一致。
与实际场景结合
这道题在真实工程里,其实有不少"换皮版本"。
比如:
-
地图渲染
- 计算某一片区域的边界长度
-
图像处理
- 统计连通区域的轮廓像素
-
游戏开发
- 判断地形边缘,用来画描边或碰撞边界
-
数据分析
- 计算某个连通块的"外部复杂度"
它们的共同点都是:
不关心内部结构,只关心"暴露在外面的边"。
时间复杂度
O(row * col)
每个格子只访问一次,每次最多检查 4 个方向。
空间复杂度
O(1)
只用了几个计数变量,没有额外的数据结构。
总结
这道题非常适合用来训练一个能力:
把"整体问题"拆成"局部贡献"的能力