在问 · 算法题解

463. 岛屿的周长

题目描述

输入 row x col 的网格 grid,1 代表陆地,0 代表水。每个格子是边长为 1 的正方形,只有上下左右相邻才算连通。

网格外围全是水。网格里恰好有一座岛,即一片连通的陆地,且岛内部没有被陆地围住的水域。

返回这座岛的周长,也就是陆地与水(含网格外部)之间分界边的总条数。

示例 1
输入:grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]
输出:16

解释:岛由 7 个陆地格组成,与水相邻的边共 16 条。

示例 2
输入:grid = [[1]]
输出:4

解释:单个陆地格四条边都挨水。

示例 3
输入:grid = [[1,0]]
输出:4

解释:陆地格右边是水,其余三边是网格外部,共 4 条。

数据范围

  • row == grid.length
  • col == grid[i].length
  • 1 <= row, col <= 100
  • grid[i][j] 只会是 0 或 1。

解题思路:迭代计数

每块陆地自带 4 条边。两块陆地相邻时,它们中间那条边两边都不算周长,要减去 2。扫描时只看上方和左边的邻居,每对相邻就恰好处理一次。

为什么正确

扫完前 k 个格子后,per 等于这些格子中陆地组成的图形的周长。

复杂度分析

时间 O(mn),空间 O(1)。

易错点

共用边要减 2 而不是 1;如果四个方向都检查,就只能减 1,否则会重复减。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])
        per = 0
        for i in range(m):
            for j in range(n):
                if grid[i][j] == 1:
                    per += 4
                    if i > 0 and grid[i - 1][j] == 1:
                        per -= 2
                    if j > 0 and grid[i][j - 1] == 1:
                        per -= 2
        return per

载入编辑器,自己跑一遍 →

其他解法

迭代计数逐格统计相邻情况,最直接;DFS 把“周长”理解为“走出岛屿的次数”,更能体现图搜索思想。

解法 2:深度优先搜索 时间 O(mn),空间 O(mn)

从任意一块陆地出发做 DFS,访问过的格子标记为 2。每当从陆地走到网格外或水域,就说明跨过了一条边界边,返回 1;走到已访问的陆地返回 0。所有返回值相加就是周长。

是岛屿类题目的通用模板,便于推广到多个岛屿等变形。需要递归栈和修改原网格,比直接计数更绕。

class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])

        def dfs(i, j):
            # 从陆地走到边界外或水域,说明跨过了一条边
            if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] == 0:
                return 1
            if grid[i][j] == 2:
                return 0
            grid[i][j] = 2
            return dfs(i - 1, j) + dfs(i + 1, j) + dfs(i, j - 1) + dfs(i, j + 1)

        for i in range(m):
            for j in range(n):
                if grid[i][j] == 1:
                    return dfs(i, j)
        return 0

数组与矩阵 专题的其他题目

查看 数组与矩阵 全部题目 →