来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-islands
岛屿数量
题目描述
给定一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,假设该网格的四条边均被水包围

题解
方法一:深度优先搜索(DFS)
将二维网格看成一个无向图,竖直或水平相邻的 1 之间有边相连。
扫描整个二维网格,若一个位置为 1,则以其为起始节点开始进行深度优先搜索。在深度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0。
最终岛屿的数量即深度优先搜索的次数。
复杂度分析
时间复杂度:O(MN)O(MN)O(MN),其中 M 和 N 分别为行数和列数。
空间复杂度:O(MN)O(MN)O(MN),在最坏情况下,整个网格均为陆地,深度优先搜索的深度达到 MN。
方法二:并查集
扫描整个二维网格。如果一个位置为 1,则将其与相邻四个方向上的 1 在并查集中进行合并union。
最终岛屿的数量就是并查集中连通分量的数目。
复杂度分析
时间复杂度:O(MN∗α(MN))O(MN * \alpha(MN))O(MN∗α(MN)),其中 M 和 N 分别为行数和列数。注意当使用路径压缩(见 find 函数)和按秩合并(见数组 rank)实现并查集时,单次操作的时间复杂度为 α(MN)\alpha(MN)α(MN),其中 α(x)\alpha(x)α(x) 为反阿克曼函数,当自变量 x 的值在人类可观测的范围内(宇宙中粒子的数量)时,函数 α(x)\alpha(x)α(x) 的值不会超过 5,因此也可以看成是常数时间复杂度。
空间复杂度:O(MN)O(MN)O(MN),即并查集需要的空间
代码
//方法二:并查集Union
class UnionFind{
public:
UnionFind(vector<vector<char>>& grid){
count = 0;
int rows = grid.size();
int cols = grid[0].size();
for(int row = 0; row < rows; row++){
for(int col = 0; col < cols; col++){
if(grid[row][col] == '1'){
parent.push_back(row*cols+col);
++count;
}
else{
parent.push_back(-1);
}
rank.push_back(0);
}
}
}
int find(int row){
if(parent[row] != row){
parent[row] = find(parent[row]);
}
return parent[row];
}
void unite(int x, int y){
int rootx = find(x);
int rooty = find(y);
if(rootx != rooty){
if(rank[rootx] < rank[rooty]){
swap(rootx, rooty);
}
parent[rooty] = rootx;
if(rank[rootx] == rank[rooty])
rank[rootx]++;
--count;
}
}
int getCount() const{
return count;
}
private:
vector<int> parent;
vector<int> rank;
int count;
};
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
/*
//方法一:深度优先搜索DFS
int rows = grid.size();
if(!rows)
return 0;
int cols = grid[0].size();//这个放在判断前,输入[]测试就会报错?
int num_islands = 0;
for(int row = 0; row < rows; row++){
for(int col = 0; col < cols; col++){
if(grid[row][col] == '1'){
++num_islands;
DFS(grid, row, col);
}
}
}
return num_islands;
}
private:
void DFS(vector<vector<char>>& grid, int row, int col){
int rows = grid.size();
int cols = grid[0].size();
grid[row][col] = '0';
if(row-1>=0 && grid[row-1][col] == '1')
DFS(grid, row-1, col);
if(row+1<rows && grid[row+1][col] == '1')
DFS(grid, row+1, col);
if(col-1>=0 && grid[row][col-1] == '1')
DFS(grid, row, col-1);
if(col+1<cols && grid[row][col+1] == '1')
DFS(grid, row, col+1);
}*/
//方法二
int rows = grid.size();
if(!rows)
return 0;
int cols = grid[0].size();
int num_islands = 0;
UnionFind uf(grid);
for(int row = 0; row < rows; row++){
for(int col = 0; col < cols; col++){
if(grid[row][col] == '1'){
grid[row][col] == '0';
if(row-1>=0 && grid[row-1][col] == '1')
uf.unite(row*cols+col, (row-1)*cols+col);
if(row+1<rows && grid[row+1][col] == '1')
uf.unite(row*cols+col, (row+1)*cols+col);
if(col-1>=0 && grid[row][col-1] == '1')
uf.unite(row*cols+col, row*cols+col-1);
if(col+1<cols && grid[row][col+1] == '1')
uf.unite(row*cols+col, row*cols+col+1);
}
}
}
return uf.getCount();
}
};
小结
DSF, BSF,union
本文介绍两种高效算法用于计算二维网格中的岛屿数量。深度优先搜索(DFS)遍历网格,标记并计数岛屿;并查集(Union-Find)则通过合并相邻陆地来统计连通分量,最终得出岛屿总数。
1万+

被折叠的 条评论
为什么被折叠?



