Files
leetcode-master/problems/kamacoder/0106.岛屿的周长.md
2025-03-17 15:52:23 +08:00

362 lines
8.2 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"><strong><a href="./qita/join.md">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们受益!</strong></p>
# 106. 岛屿的周长
[卡码网题目链接ACM模式](https://kamacoder.com/problempage.php?pid=1178)
题目描述
给定一个由 1陆地和 0组成的矩阵岛屿是被水包围并且通过水平方向或垂直方向上相邻的陆地连接而成的。
你可以假设矩阵外均被水包围。在矩阵中恰好拥有一个岛屿,假设组成岛屿的陆地边长都为 1请计算岛屿的周长。岛屿内部没有水域。
输入描述
第一行包含两个整数 N, M表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0表示岛屿的单元格。
输出描述
输出一个整数,表示岛屿的周长。
输入示例
```
5 5
0 0 0 0 0
0 1 0 1 0
0 1 1 1 0
0 1 1 1 0
0 0 0 0 0
```
输出示例
14
提示信息
![](https://file.kamacoder.com/pics/20240524115244.png)
岛屿的周长为 14。
数据范围:
1 <= M, N <= 50。
## 思路
岛屿问题最容易让人想到BFS或者DFS但本题确实还用不上。
为了避免大家惯性思维,所以给大家安排了这道题目。
### 解法一:
遍历每一个空格,遇到岛屿则计算其上下左右的空格情况。
如果该陆地上下左右的空格是有水域,则说明是一条边,如图:
![](https://file.kamacoder.com/pics/20240524115933.png)
陆地的右边空格是水域,则说明找到一条边。
如果该陆地上下左右的空格出界了,则说明是一条边,如图:
![](https://file.kamacoder.com/pics/20240524120105.png)
该陆地的下边空格出界了,则说明找到一条边。
C++代码如下:(详细注释)
```CPP
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> grid(n, vector<int>(m, 0));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
int direction[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
int result = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; 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 // x在边界上
|| x >= grid.size() // x在边界上
|| y < 0 // y在边界上
|| y >= grid[0].size() // y在边界上
|| grid[x][y] == 0) { // x,y位置是水域
result++;
}
}
}
}
}
cout << result << endl;
}
```
### 解法二:
计算出总的岛屿数量,总的变数为:岛屿数量 * 4
因为有一对相邻两个陆地边的总数就要减2如图红线部分有两个陆地相邻总边数就要减2
![](https://file.kamacoder.com/pics/20240524120855.png)
那么只需要在计算出相邻岛屿的数量就可以了相邻岛屿数量为cover。
结果 result = 岛屿数量 * 4 - cover * 2;
C++代码如下:(详细注释)
```CPP
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> grid(n, vector<int>(m, 0));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
int sum = 0; // 陆地数量
int cover = 0; // 相邻数量
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; 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++;
// 为什么没统计下边和右边? 因为避免重复计算
}
}
}
cout << sum * 4 - cover * 2 << endl;
}
```
## 其他语言版本
### Java
```Java
import java.util.*;
public class Main {
// 每次遍历到1探索其周围4个方向并记录周长最终合计
// 声明全局变量dirs表示4个方向
static int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
// 统计每单个1的周长
static int count;
// 探索其周围4个方向并记录周长
public static void helper(int[][] grid, int x, int y) {
for (int[] dir : dirs) {
int nx = x + dir[0];
int ny = y + dir[1];
// 遇到边界或者水,周长加一
if (nx < 0 || nx >= grid.length || ny < 0 || ny >= grid[0].length
|| grid[nx][ny] == 0) {
count++;
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 接收输入
int M = sc.nextInt();
int N = sc.nextInt();
int[][] grid = new int[M][N];
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
grid[i][j] = sc.nextInt();
}
}
int result = 0; // 总周长
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
if (grid[i][j] == 1) {
count = 0;
helper(grid, i, j);
// 更新总周长
result += count;
}
}
}
// 打印结果
System.out.println(result);
}
}
```
### Python
```python
def main():
import sys
input = sys.stdin.read
data = input().split()
# 读取 n 和 m
n = int(data[0])
m = int(data[1])
# 初始化 grid
grid = []
index = 2
for i in range(n):
grid.append([int(data[index + j]) for j in range(m)])
index += m
sum_land = 0 # 陆地数量
cover = 0 # 相邻数量
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
sum_land += 1
# 统计上边相邻陆地
if i - 1 >= 0 and grid[i - 1][j] == 1:
cover += 1
# 统计左边相邻陆地
if j - 1 >= 0 and grid[i][j - 1] == 1:
cover += 1
# 不统计下边和右边,避免重复计算
result = sum_land * 4 - cover * 2
print(result)
if __name__ == "__main__":
main()
```
### Go
```go
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
line := scanner.Text()
n, m := parseInput(line)
// 初始化 grid
grid := make([][]int, n)
for i := range grid {
grid[i] = make([]int, m)
}
// 读入 grid 数据
for i := 0; i < n; i++ {
scanner.Scan()
line := scanner.Text()
values := parseLine(line, m)
for j := 0; j < m; j++ {
grid[i][j] = values[j]
}
}
sum := 0 // 陆地数量
cover := 0 // 相邻数量
for i := 0; i < n; i++ {
for j := 0; j < m; 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++
}
// 为什么没统计下边和右边? 因为避免重复计算
}
}
}
fmt.Println(sum*4 - cover*2)
}
// parseInput 解析 n 和 m
func parseInput(line string) (int, int) {
parts := strings.Split(line, " ")
n, _ := strconv.Atoi(parts[0])
m, _ := strconv.Atoi(parts[1])
return n, m
}
// parseLine 解析一行中的多个值
func parseLine(line string, count int) []int {
parts := strings.Split(line, " ")
values := make([]int, count)
for i := 0; i < count; i++ {
values[i], _ = strconv.Atoi(parts[i])
}
return values
}
```
### Rust
### JavaScript
### TypeScript
### PhP
### Swift
### Scala
### C#
### Dart
### C