LeetCode 463 - 岛屿的周长


文章目录

摘要

这道题乍一看是个"地图题",很多人第一反应可能是 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 > 0
  • i < rows - 1
  • j > 0
  • j < 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

和题目给出的示例完全一致。

与实际场景结合

这道题在真实工程里,其实有不少"换皮版本"。

比如:

  1. 地图渲染

    • 计算某一片区域的边界长度
  2. 图像处理

    • 统计连通区域的轮廓像素
  3. 游戏开发

    • 判断地形边缘,用来画描边或碰撞边界
  4. 数据分析

    • 计算某个连通块的"外部复杂度"

它们的共同点都是:

不关心内部结构,只关心"暴露在外面的边"。

时间复杂度

复制代码
O(row * col)

每个格子只访问一次,每次最多检查 4 个方向。

空间复杂度

复制代码
O(1)

只用了几个计数变量,没有额外的数据结构。

总结

这道题非常适合用来训练一个能力:

把"整体问题"拆成"局部贡献"的能力

相关推荐
l1t1 天前
对clickhouse给出的二分法求解Advent of Code 2025第10题 电子工厂 第二部分的算法理解
数据库·算法·clickhouse
Tisfy1 天前
LeetCode 3315.构造最小位运算数组 II:位运算
算法·leetcode·题解·位运算
YuTaoShao1 天前
【LeetCode 每日一题】1292. 元素和小于等于阈值的正方形的最大边长
算法·leetcode·职场和发展
Remember_9931 天前
【数据结构】深入理解Map和Set:从搜索树到哈希表的完整解析
java·开发语言·数据结构·算法·leetcode·哈希算法·散列表
浅念-1 天前
C++第一课
开发语言·c++·经验分享·笔记·学习·算法
charlie1145141911 天前
现代嵌入式C++教程:对象池(Object Pool)模式
开发语言·c++·学习·算法·嵌入式·现代c++·工程实践
燃于AC之乐1 天前
我的算法修炼之路--8——预处理、滑窗优化、前缀和哈希同余,线性dp,图+并查集与逆向图
算法·哈希算法·图论·滑动窗口·哈希表·线性dp
格林威1 天前
多相机重叠视场目标关联:解决ID跳变与重复计数的 8 个核心策略,附 OpenCV+Halcon 实战代码!
人工智能·数码相机·opencv·算法·计算机视觉·分类·工业相机
郝学胜-神的一滴1 天前
深入理解网络分层模型:数据封包与解包全解析
linux·开发语言·网络·程序人生·算法
永远都不秃头的程序员(互关)1 天前
【K-Means深度探索(九)】K-Means与数据预处理:特征缩放与降维的重要性!
算法·机器学习·kmeans