leetcode-master/problems/0463.岛屿的周长.md

258 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.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/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;
}
}
// 解法二
class Solution {
public int islandPerimeter(int[][] grid) {
// 计算岛屿的周长
// 方法二 : 遇到相邻的陆地总周长就-2
int landSum = 0; // 陆地数量
int cover = 0; // 相邻陆地数量
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == 1) {
landSum++;
// 统计上面和左边的相邻陆地
if(i - 1 >= 0 && grid[i-1][j] == 1) cover++;
if(j - 1 >= 0 && grid[i][j-1] == 1) cover++;
}
}
}
return landSum * 4 - cover * 2;
}
}
```
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
```go
func islandPerimeter(grid [][]int) int {
m, n := len(grid), len(grid[0])
res := 0
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if grid[i][j] == 1 {
res += 4
// 上下左右四个方向
if i > 0 && grid[i-1][j] == 1 {res--} // 上边有岛屿
if i < m-1 && grid[i+1][j] == 1 {res--} // 下边有岛屿
if j > 0 && grid[i][j-1] == 1 {res--} // 左边有岛屿
if j < n-1 && grid[i][j+1] == 1 {res--} // 右边有岛屿
}
}
}
return res
}
```
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;
};
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>