Leetcode 200:岛屿数量
给你一个由 '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.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j]
的值为'0'
或'1'
代码均为ACM模式
BFS:
#include <bits/stdc++.h>
using namespace std;
void bfs(vector<vector<char>> &grid, int i, int j)
{
int m = grid.size();
int n = grid[0].size();
queue<pair<int, int>> q;
q.push({i, j});
grid[i][j] = '0';
int dx[] = {-1, 0, 0, 1};
int dy[] = {0, -1, 1, 0};
while (!q.empty())
{
auto [x, y] = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] == '1')
{
q.push({nx, ny});
grid[nx][ny] = '0';
}
}
}
}
int numcnt(vector<vector<char>> &grid)
{
if (grid.empty())
return 0;
int cnt = 0;
int m = grid.size();
int n = grid[0].size();
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (grid[i][j] == '1')
{
bfs(grid, i, j);
cnt++;
}
}
}
return cnt;
}
int main()
{
int n, m;
cin >> m >> n;
vector<vector<char>> grid(m, vector<char>(n));
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
cin >> grid[i][j];
}
}
int res = numcnt(grid);
cout << res << endl;
return 0;
}
DFS:
#include <bits/stdc++.h>
using namespace std;
int m, n;
int dx[] = {-1, 0, 0, 1}; // 上、左、右、下
int dy[] = {0, -1, 1, 0};
void dfs(vector<vector<char>> &grid, int x, int y) {
grid[x][y] = '0'; // 标记为已访问
for (int k = 0; k < 4; ++k) {
int nx = x + dx[k];
int ny = y + dy[k];
if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] == '1') {
dfs(grid, nx, ny);
}
}
}
int numIslands(vector<vector<char>> &grid) {
int count = 0;
m = grid.size();
n = grid[0].size();
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == '1') {
dfs(grid, i, j);
count++;
}
}
}
return count;
}
int main() {
cin >> m >> n;
vector<vector<char>> grid(m, vector<char>(n));
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
cin >> grid[i][j];
cout << numIslands(grid) << endl;
return 0;
}
并查集
#include <bits/stdc++.h>
using namespace std;
int m, n;
int dx[] = {-1, 0, 0, 1};
int dy[] = {0, -1, 1, 0};
vector<int> parent, rank;
int find(int x) {
if (parent[x] != x)
parent[x] = find(parent[x]); // 路径压缩
return parent[x];
}
void unite(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) return;
if (rank[rootX] < rank[rootY]) {
parent[rootX] = rootY;
} else if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
} else {
parent[rootY] = rootX;
rank[rootX]++;
}
}
int numIslands(vector<vector<char>> &grid) {
m = grid.size();
n = grid[0].size();
parent.resize(m * n);
rank.resize(m * n, 0);
int count = 0;
// 初始化
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
int id = i * n + j;
if (grid[i][j] == '1') {
parent[id] = id;
count++;
}
}
}
// 合并相邻陆地
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 ni = i + dx[k];
int nj = j + dy[k];
if (ni >= 0 && ni < m && nj >= 0 && nj < n && grid[ni][nj] == '1') {
int id1 = i * n + j;
int id2 = ni * n + nj;
if (find(id1) != find(id2)) {
unite(id1, id2);
count--;
}
}
}
}
}
}
return count;
}
int main() {
cin >> m >> n;
vector<vector<char>> grid(m, vector<char>(n));
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
cin >> grid[i][j];
cout << numIslands(grid) << endl;
return 0;
}
维度 | DFS | BFS |
---|---|---|
搜索结构 | 栈(递归实现) | 队列 |
内存消耗 | 深度大时递归栈可能爆栈 | 需要队列,空间开销稳定 |
实现难度 | 简单,几行递归代码 | 稍复杂,需要管理队列 |
扩展顺序 | 先深入一条路径再回溯 | 逐层扩展,先近后远 |
适用场景 | 小地图、连通块较少 | 大地图、连通块较多、避免栈溢出 |
算法 | 时间复杂度 | 空间复杂度 |
---|---|---|
DFS | O(m × n) | O(m × n)(递归栈深度) |
BFS | O(m × n) | O(m × n)(队列大小) |
Union-Find | O(m × n * α(mn)) | O(m × n)(parent数组) |