Medium
题目描述
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
输出:1
示例 2:
输入:grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3
提示:
m == grid.lengthn == grid[i].length1 <= m, n <= 300grid[i][j]的值为'0'或'1'
解题思路
这是一道经典的图论问题,可以用多种方法解决:
方法一:深度优先搜索(DFS)
遍历网格,当遇到陆地 '1' 时,启动DFS将整个岛屿标记为已访问(改为 '0'),然后岛屿计数加一。DFS会递归访问当前位置的上下左右四个方向,将所有相连的陆地都标记完毕。
方法二:广度优先搜索(BFS) 思路类似DFS,但使用队列进行层序遍历,逐层扩展到相邻的陆地。
方法三:并查集 将所有陆地格子看作节点,相邻的陆地进行合并操作,最终统计连通分量的个数。
推荐解法:DFS DFS实现简洁,空间复杂度相对较低,是最常用的解法。通过原地修改网格避免额外的访问数组,节省空间。
核心思想是:每发现一个未访问的陆地,就用DFS将整个岛屿"淹没",确保同一岛屿不会被重复计算。
代码实现
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
if (grid.empty() || grid[0].empty()) return 0;
int m = grid.size(), n = grid[0].size();
int count = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == '1') {
count++;
dfs(grid, i, j);
}
}
}
return count;
}
private:
void dfs(vector<vector<char>>& grid, int i, int j) {
int m = grid.size(), n = grid[0].size();
if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == '0') {
return;
}
grid[i][j] = '0'; // 标记为已访问
dfs(grid, i + 1, j);
dfs(grid, i - 1, j);
dfs(grid, i, j + 1);
dfs(grid, i, j - 1);
}
};
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
if not grid or not grid[0]:
return 0
m, n = len(grid), len(grid[0])
count = 0
def dfs(i, j):
if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] == '0':
return
grid[i][j] = '0' # 标记为已访问
dfs(i + 1, j)
dfs(i - 1, j)
dfs(i, j + 1)
dfs(i, j - 1)
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
count += 1
dfs(i, j)
return count
public class Solution {
public int NumIslands(char[][] grid) {
if (grid == null || grid.Length == 0 || grid[0].Length == 0) {
return 0;
}
int m = grid.Length, n = grid[0].Length;
int count = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == '1') {
count++;
DFS(grid, i, j);
}
}
}
return count;
}
private void DFS(char[][] grid, int i, int j) {
int m = grid.Length, n = grid[0].Length;
if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == '0') {
return;
}
grid[i][j] = '0'; // 标记为已访问
DFS(grid, i + 1, j);
DFS(grid, i - 1, j);
DFS(grid, i, j + 1);
DFS(grid, i, j - 1);
}
}
var numIslands = function(grid) {
if (!grid || grid.length === 0) return 0;
const m = grid.length;
const n = grid[0].length;
let count = 0;
function dfs(i, j) {
if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] === '0') {
return;
}
grid[i][j] = '0';
dfs(i + 1, j);
dfs(i - 1, j);
dfs(i, j + 1);
dfs(i, j - 1);
}
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (grid[i][j] === '1') {
count++;
dfs(i, j);
}
}
}
return count;
};
复杂度分析
| 解法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| DFS | O(m × n) | O(m × n) |
| BFS | O(m × n) | O(min(m, n)) |
| 并查集 | O(m × n × α(m × n)) | O(m × n) |
说明:
- 时间复杂度:每个格子最多访问一次,总共 m × n 个格子
- 空间复杂度:DFS 最坏情况下递归深度为 m × n(整个网格都是陆地且呈一条直线)
相关题目
130. Surrounded Regions (Medium)
419. Battleships in a Board (Medium)
695. Max Area of Island (Medium)
1905. Count Sub Islands (Medium)
1992. Find All Groups of Farmland (Medium)
2316. Count Unreachable Pairs of Nodes in an Undirected Graph (Medium)
3619. Count Islands With Total Value Divisible by K (Medium)