MongoDB 4.x——合理使用索引(二)
2026/7/24 12:28:34
这道题乍一看是个“地图题”,很多人第一反应可能是 DFS / BFS,甚至想去模拟整条边界走一圈。但其实这是一道非常典型的“把问题拆小”的题。
你根本不需要真的去“绕岛一周”,只要站在每一块陆地的角度,问一句话就够了:
我这块地,有几条边是暴露在水里的?
把这个问题想清楚,代码会非常简单,而且几乎不可能写错。
题目给你一个二维网格grid:
1表示陆地0表示水域已知条件非常友好:
每一个格子都是边长为 1 的正方形,你需要计算:
这个岛屿的总周长
这道题最清晰、最不容易出 bug 的解法可以用一句话概括:
每一块陆地默认贡献 4 条边,每和另一块陆地相邻一次,就少 1 条边。
换句话说:
遍历整个网格
遇到一块陆地
最后所有陆地的贡献加起来,就是岛屿的周长。
这个很直观:
当两块陆地挨在一起时,比如左右相邻:
[1][1]它们中间那条边,其实是“内部边”,不属于周长。
而且要注意一个细节:
所以:
-1不会。
因为我们是站在每一块陆地的角度算自己的边,不是在算“边本身”。
每一条真正的外边,只会被某一块陆地算一次。
importFoundationclassSolution{funcislandPerimeter(_grid:[[Int]])->Int{letrows=grid.countletcols=grid[0].countvarperimeter=0foriin0..<rows{forjin0..<cols{ifgrid[i][j]==1{// 每块陆地默认 4 条边perimeter+=4// 上ifi>0&&grid[i-1][j]==1{perimeter-=1}// 下ifi<rows-1&&grid[i+1][j]==1{perimeter-=1}// 左ifj>0&&grid[i][j-1]==1{perimeter-=1}// 右ifj<cols-1&&grid[i][j+1]==1{perimeter-=1}}}}returnperimeter}}ifgrid[i][j]==1{perimeter+=4}只要是陆地,先把 4 条边加上,这是“理论最大值”。
ifi>0&&grid[i-1][j]==1{perimeter-=1}检查上方是否是陆地:
上下左右四个方向完全一样的逻辑。
每次检查前都先判断:
i > 0i < rows - 1j > 0j < cols - 1这也是写网格题时非常重要的一个习惯。
letsolution=Solution()letgrid1=[[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]print(solution.islandPerimeter(grid1))// 16letgrid2=[[1]]print(solution.islandPerimeter(grid2))// 4letgrid3=[[1,0]]print(solution.islandPerimeter(grid3))// 4输出结果:
16 4 4和题目给出的示例完全一致。
这道题在真实工程里,其实有不少“换皮版本”。
比如:
地图渲染
图像处理
游戏开发
数据分析
它们的共同点都是:
不关心内部结构,只关心“暴露在外面的边”。
O(row * col)每个格子只访问一次,每次最多检查 4 个方向。
O(1)只用了几个计数变量,没有额外的数据结构。
这道题非常适合用来训练一个能力:
把“整体问题”拆成“局部贡献”的能力