216 lines
7.2 KiB
Markdown
216 lines
7.2 KiB
Markdown
<p align="center">
|
||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||
<img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20210924105952.png" width="1000"/>
|
||
</a>
|
||
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||
# 463. 岛屿的周长
|
||
|
||
[力扣题目链接](https://leetcode-cn.com/problems/island-perimeter/)
|
||
|
||
## 思路
|
||
|
||
岛屿问题最容易让人想到BFS或者DFS,但是这道题还真的没有必要,别把简单问题搞复杂了。
|
||
|
||
### 解法一:
|
||
|
||
遍历每一个空格,遇到岛屿,计算其上下左右的情况,遇到水域或者出界的情况,就可以计算边了。
|
||
|
||
如图:
|
||
|
||
<img src='https://code-thinking.cdn.bcebos.com/pics/463.岛屿的周长.png' width=600> </img></div>
|
||
|
||
C++代码如下:(详细注释)
|
||
|
||
```CPP
|
||
class Solution {
|
||
public:
|
||
int direction[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
|
||
int islandPerimeter(vector<vector<int>>& grid) {
|
||
int result = 0;
|
||
for (int i = 0; i < grid.size(); i++) {
|
||
for (int j = 0; j < grid[0].size(); j++) {
|
||
if (grid[i][j] == 1) {
|
||
for (int k = 0; k < 4; k++) { // 上下左右四个方向
|
||
int x = i + direction[k][0];
|
||
int y = j + direction[k][1]; // 计算周边坐标x,y
|
||
if (x < 0 // i在边界上
|
||
|| x >= grid.size() // i在边界上
|
||
|| y < 0 // j在边界上
|
||
|| y >= grid[0].size() // j在边界上
|
||
|| grid[x][y] == 0) { // x,y位置是水域
|
||
result++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
};
|
||
```
|
||
|
||
### 解法二:
|
||
|
||
计算出总的岛屿数量,因为有一对相邻两个陆地,边的总数就减2,那么在计算出相邻岛屿的数量就可以了。
|
||
|
||
result = 岛屿数量 * 4 - cover * 2;
|
||
|
||
如图:
|
||
|
||
<img src='https://code-thinking.cdn.bcebos.com/pics/463.岛屿的周长1.png' width=600> </img></div>
|
||
|
||
C++代码如下:(详细注释)
|
||
|
||
```CPP
|
||
class Solution {
|
||
public:
|
||
int islandPerimeter(vector<vector<int>>& grid) {
|
||
int sum = 0; // 陆地数量
|
||
int cover = 0; // 相邻数量
|
||
for (int i = 0; i < grid.size(); i++) {
|
||
for (int j = 0; j < grid[0].size(); j++) {
|
||
if (grid[i][j] == 1) {
|
||
sum++;
|
||
// 统计上边相邻陆地
|
||
if(i - 1 >= 0 && grid[i - 1][j] == 1) cover++;
|
||
// 统计左边相邻陆地
|
||
if(j - 1 >= 0 && grid[i][j - 1] == 1) cover++;
|
||
// 为什么没统计下边和右边? 因为避免重复计算
|
||
}
|
||
}
|
||
}
|
||
return sum * 4 - cover * 2;
|
||
}
|
||
};
|
||
```
|
||
|
||
|
||
## 其他语言版本
|
||
|
||
Java:
|
||
|
||
```java
|
||
// 解法一
|
||
class Solution {
|
||
// 上下左右 4 个方向
|
||
int[] dirx = {-1, 1, 0, 0};
|
||
int[] diry = {0, 0, -1, 1};
|
||
|
||
public int islandPerimeter(int[][] grid) {
|
||
int m = grid.length;
|
||
int n = grid[0].length;
|
||
int res = 0; // 岛屿周长
|
||
for (int i = 0; i < m; i++) {
|
||
for (int j = 0; j < n; j++) {
|
||
if (grid[i][j] == 1) {
|
||
for (int k = 0; k < 4; k++) {
|
||
int x = i + dirx[k];
|
||
int y = j + diry[k];
|
||
// 当前位置是陆地,并且从当前位置4个方向扩展的“新位置”是“水域”或“新位置“越界,则会为周长贡献一条边
|
||
if (x < 0 || x >= m || y < 0 || y >= n || grid[x][y] == 0) {
|
||
res++;
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
}
|
||
```
|
||
|
||
Python:
|
||
### 解法1:
|
||
扫描每个cell,如果当前位置为岛屿 grid[i][j] == 1, 从当前位置判断四边方向,如果边界或者是水域,证明有边界存在,res矩阵的对应cell加一。
|
||
|
||
```python
|
||
class Solution:
|
||
def islandPerimeter(self, grid: List[List[int]]) -> int:
|
||
|
||
m = len(grid)
|
||
n = len(grid[0])
|
||
|
||
# 创建res二维素组记录答案
|
||
res = [[0] * n for j in range(m)]
|
||
|
||
for i in range(m):
|
||
for j in range(len(grid[i])):
|
||
# 如果当前位置为水域,不做修改或reset res[i][j] = 0
|
||
if grid[i][j] == 0:
|
||
res[i][j] = 0
|
||
# 如果当前位置为陆地,往四个方向判断,update res[i][j]
|
||
elif grid[i][j] == 1:
|
||
if i == 0 or (i > 0 and grid[i-1][j] == 0):
|
||
res[i][j] += 1
|
||
if j == 0 or (j >0 and grid[i][j-1] == 0):
|
||
res[i][j] += 1
|
||
if i == m-1 or (i < m-1 and grid[i+1][j] == 0):
|
||
res[i][j] += 1
|
||
if j == n-1 or (j < n-1 and grid[i][j+1] == 0):
|
||
res[i][j] += 1
|
||
|
||
# 最后求和res矩阵,这里其实不一定需要矩阵记录,可以设置一个variable res 记录边长,舍矩阵无非是更加形象而已
|
||
ans = sum([sum(row) for row in res])
|
||
|
||
return ans
|
||
|
||
```
|
||
|
||
Go:
|
||
|
||
JavaScript:
|
||
```javascript
|
||
//解法一
|
||
var islandPerimeter = function(grid) {
|
||
// 上下左右 4 个方向
|
||
const dirx = [-1, 1, 0, 0], diry = [0, 0, -1, 1];
|
||
const m = grid.length, n = grid[0].length;
|
||
let res = 0; //岛屿周长
|
||
for(let i = 0; i < m; i++){
|
||
for(let j = 0; j < n; j++){
|
||
if(grid[i][j] === 1){
|
||
for(let k = 0; k < 4; k++){ //上下左右四个方向
|
||
// 计算周边坐标的x,y
|
||
let x = i + dirx[k];
|
||
let y = j + diry[k];
|
||
// 四个方向扩展的新位置是水域或者越界就会为周长贡献1
|
||
if(x < 0 // i在边界上
|
||
|| x >= m // i在边界上
|
||
|| y < 0 // j在边界上
|
||
|| y >= n // j在边界上
|
||
|| grid[x][y] === 0){ // (x,y)位置是水域
|
||
res++;
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return res;
|
||
};
|
||
|
||
//解法二
|
||
var islandPerimeter = function(grid) {
|
||
let sum = 0; // 陆地数量
|
||
let cover = 0; // 相邻数量
|
||
for(let i = 0; i < grid.length; i++){
|
||
for(let j = 0; j <grid[0].length; j++){
|
||
if(grid[i][j] === 1){
|
||
sum++;
|
||
// 统计上边相邻陆地
|
||
if(i - 1 >= 0 && grid[i-1][j] === 1) cover++;
|
||
// 统计左边相邻陆地
|
||
if(j - 1 >= 0 && grid[i][j-1] === 1) cover++;
|
||
// 为什么没统计下边和右边? 因为避免重复计算
|
||
}
|
||
}
|
||
}
|
||
return sum * 4 - cover * 2;
|
||
};
|
||
```
|
||
|
||
|
||
-----------------------
|
||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|