岛屿的周长
题目
给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。
网格中的格子水平和垂直方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
示例
输入:grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]
输出:16
解释:它的周长是上面图片中的 16 个黄色的边
题解
方法 1 迭代
由题可知需要计算这个岛屿的周长,对于一个陆地格子的每条边,它被算作岛屿的周长当且仅当这条边为网格的边界或者相邻的另一个格子为水域。因此,可以通过遍历每个陆地格子,判断其四个方向是否为边界或水域,若是则计入周长,采用迭代法累加得出最终结果。
注:迭代和递归的区别
- 递归:指程序调用自身的编程思想,即重复调用函数自身实现循环。
- 递归与普通循环:循环是有去无回,而递归则是有去有回(因为存在终止条件)。
- 迭代:利用已知的变量值,根据递推公式不断演进得到变量新值的编程思想,即函数内某段代码实现循环。
- 迭代与普通循环:迭代时,循环代码中参与运算的变量同时是保存结果的变量,当前保存的结果作为下一次循环计算的初始值。
方法 2 深度优先搜索
为了求出岛屿周长,可以采用深度优先搜索遍历的方法,可拓展至统计多个岛屿各自的周长。
注意:为了避免陆地格子被重复遍历导致死循环,需要设置变量标记陆地格子是否已经访问过。
代码
方法 1 迭代
- constexpr 和 const 的区别:
凡是表达“只读”语义的场景都使用 const,表达“常量”语义的场景都使用 constexpr。
const:表明这个值是常量,但是不必在编译期确定
constexpr:表明这个值不仅是常量,而且也是编译期确定的 - 表示相邻位置(上下左右四个方向)时可以用
dx[4]={0,0,-1,1}
dy[4]={1,-1,0,0}
class Solution {
constexpr static int dx[4]={0,0,-1,1};
constexpr static int dy[4]={1,-1,0,0};
public:
int islandPerimeter(vector<vector<int>>& grid) {
int n=grid.size(),m=grid[0].size();
int ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
//对于每一个小格子
if(grid[i][j]){
//对于每一条边
for(int k=0;k<4;k++){
int tx=i+dx[k];
int ty=j+dy[k];
//若相邻位置是否为边界或水域则该边计入周长
if(tx<0||tx>=n||ty<0||ty>=m||!grid[tx][ty]){
ans++;
}
}
}
}
}
return ans;
}
};
方法 2 深度优先搜索
class Solution {
constexpr static int dx[4]={0,1,-1,0};
constexpr static int dy[4]={-1,0,0,1};
public:
//深度优先搜索遍历
int dfs(int i,int j,vector<vector<int>>& grid,int n,int m){
//判断该边是否计入周长
if(i<0||i>=n||j<0||j>=m||!grid[i][j]){
return 1;
}
//判断是否已经访问
if(grid[i][j]==2){
return 0;
}
//标记该格子已被访问
grid[i][j]=2;
int res=0;
//对于格子的四条边进行判断
for(int k=0;k<4;k++){
int tx=i+dx[k];
int ty=j+dy[k];
res+=dfs(tx,ty,grid,n,m);
}
return res;
}
//计算岛屿周长
int islandPerimeter(vector<vector<int>>& grid) {
int n=grid.size(),m=grid[0].size();
int ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(grid[i][j]==1){
ans+=dfs(i,j,grid,n,m);
}
}
}
return ans;
}
};