463. 岛屿的周长
题目描述
给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。
网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
解题思路
思路一:DFS(深度优先搜索)
岛屿的周长就是岛屿方格和非岛屿方格相邻的边的数量。注意,这里的非岛屿方格,既包括水域方格,也包括网格的边界。
对应到 DFS 遍历中,就是:每当在 DFS 遍历中,从一个岛屿方格走向一个非岛屿方格,就将周长加 1。
实现代码如下:
/**
* @param {number[][]} grid
* @return {number}
*/
var islandPerimeter = function(grid) {
let res = 0, rowLen = grid.length, colLen = grid[0].length;
const dfs = function (row, col) {
// 从一个岛屿方格走向网格边界、水域方格,周长加 1
if (row < 0 || row >= rowLen || col < 0 || col >= colLen || grid[row][col] == 0) {
return 1;
}
// 已遍历过(值为2)的岛屿在这里会直接返回,不会重复遍历
if (grid[row][col] != 1) {
return 0;
}
grid[row][col] = 2; // 标记为已遍历的
return dfs(row, col - 1) + dfs(row - 1, col) + dfs(row + 1, col) + dfs(row, col + 1);
}
for (let row = 0; row < rowLen; row++) {
for (let col = 0; col < colLen; col++) {
if (grid[row][col] == 1) {
res += dfs(row, col);
}
}
}
return res;
};
-
时间复杂度:O(nm),其中 n 为网格的高度,m 为网格的宽度。每个格子至多会被遍历一次,因此总时间复杂度为 O(nm)。
-
空间复杂度:O(nm)。深度优先搜索复杂度取决于递归的栈空间,而栈空间最坏情况下会达到 O(nm)。
思路二: 普通遍历
遍历整个数组,碰到0或者边界计数
/**
* @param {number[][]} grid
* @return {number}
*/
var islandPerimeter = function(grid) {
let count = 0, rowLen = grid.length, colLen = grid[0].length;
for (let row = 0; row < rowLen; row++) {
for (let col = 0; col < colLen; col++) {
if (grid[row][col] == 1) {
if (row == 0 || grid[row - 1][col] == 0) count++;
if (row == rowLen - 1 || grid[row + 1][col] == 0) count++;
if (col == 0 || grid[row][col - 1] == 0) count++;
if (col == colLen - 1 || grid[row][col + 1] == 0) count++;
}
}
}
return count;
};
思路如下:
一块土地 4 个周长,但岛上的土地存在接壤,每一块接壤,会减掉 2 个边长。
所以,总周长 = 4 * 土地个数 - 2 * 接壤边的条数。
遍历矩阵,遍历到土地,就 land++,如果它的右/下边也是土地,则 border++,遍历结束后代入公式
实现代码如下:
/**
* @param {number[][]} grid
* @return {number}
*/
var islandPerimeter = function(grid) {
let land = 0, // 岛屿格子数量
edge = 0, // 岛屿格子之间的相邻边
rowLen = grid.length, colLen = grid[0].length;
for (let row = 0; row < rowLen; row++) {
for (let col = 0; col < colLen; col++) {
if (grid[row][col] == 1) {
land++;
// 判断右边是不是 陆地格子
if (row < rowLen - 1 && grid[row + 1][col] == 1) {
edge++;
}
// 判断下面是不是 陆地格子
if (col < colLen - 1 && grid[row][col + 1] == 1) {
edge++;
}
}
}
}
return 4 * land - 2 * edge;
};