本文参考岛屿数量
问题描述
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例1:
输入:
11110
11010
11000
00000
输出: 1
示例2:
输入:
11000
11000
00100
00011
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。
分析:通俗来讲,本题是求给定的二维网格中可以划分几块区域,自然而然想到用并查集来做,也可以看做图来分析,‘1’为顶点,水平或竖直方向上相邻的‘1’为边,然后用BFS或DFS进行遍历,每次遍历完一块区域,岛屿树+1
并查集
按树(集合)的高度,也就是秩(rank)合并, n ∗ i + j n*i+j n∗i+j 作为元素标识
class UnionFind{
public:
UnionFind(vector<vector<char>>& grid){
count=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'){
parent.push_back(n*i+j);
count++;
}else parent.push_back(-1);
rank.push_back(0);
}
}
}
//find元素i所在树的根
int find(int i){
if(parent[i]!=i){
parent[i]=find(parent[i]); //自己不是根,那就看父亲
}
return parent[i];
}
//合并两元素就是合并这俩元素所在的树,union是C关键字,所以函数名unite
void unite(int x,int y){
int rootx=find(x);
int rooty=find(y);
if(rootx!=rooty){
//按rank(也就是树高度)大小合并
if(rank[rootx]<rank[rooty]){
swap(rootx,rooty);
}
parent[rooty]=rootx;
if(rank[rootx]==rank[rooty]) rank[rootx]++;
count--;
}
}
//count表示树的个数
int get_count() const{
return count;
}
private:
vector<int> rank;
vector<int> parent;
int count;
};
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
int nr=grid.size();
if(nr==0) return 0;
int nc=grid[0].size();
UnionFind uf(grid);
for(int r=0;r<nr;r++){
for(int c=0;c<nc;c++){
if(grid[r][c]=='1'){
grid[r][c]='0';
if(r-1>=0&&grid[r-1][c]=='1') uf.unite(r*nc+c,(r-1)*nc+c);
if(r+1<nr&&grid[r+1][c]=='1') uf.unite(r*nc+c,(r+1)*nc+c);
if(c-1>=0&&grid[r][c-1]=='1') uf.unite(r*nc+c,r*nc+c-1);
if(c+1<nc&&grid[r][c+1]=='1') uf.unite(r*nc+c,r*nc+c+1);
}
}
}
return uf.get_count();
}
};
DFS
这里贴一个DFS的通用模板(伪代码)
void Dfs(Vertex V){
Visited[V]=True;
for each W adjacent to V
if(!Visited[W])
Dfs(W);
}
直接来看题解
class Solution{
public:
void dfs(int r,int c){
int nr=grid.size();
int nc=grid[0].size();
grid[r][c]='0';
if(r-1>=0 && grid[r-1][c]=='1') dfs(r-1,c);
if(r+1<nr && grid[r+1][c]=='1') dfs(r+1,c);
if(c-1>=0 && grid[r][c-1]=='1') dfs(r,c-1);
if(c+1<nc && grid[r][c+1]=='1') dfs(r,c+1);
}
int numIslands(vector<vector<char>>& grid){
int m=grid.size();
if(m==0) return 0;
int n=grid[0].size();
this->grid=grid;
int num_islands=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(this->grid[i][j]=='1'){
dfs(i,j);
num_islands++;
}
}
}
return num_islands;
}
private:
vector<vector<char>> grid;
};
BFS
无权最短路径算法、Dijkstra 算法 都是 BFS 的经典算法,按层处理节点
class Solution{
public:
int numIslands(vector<vector<char>>& grid){
int m=grid.size();
if(m==0) return 0;
int n=grid[0].size();
grid=grid;
int num_islands=0;
queue<pair<int,int>> q;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(grid[i][j]=='1'){
num_islands++;
grid[i][j]='0';
q.push({i,j});
while(!q.empty()){
auto rc=q.front();
q.pop();
int r=rc.first, c=rc.second;
if(r-1>=0 && grid[r-1][c]=='1') {
q.push({r-1,c});
grid[r-1][c]='0';
}
if(r+1<m && grid[r+1][c]=='1') {
q.push({r+1,c});
grid[r+1][c]='0';
};
if(c-1>=0 && grid[r][c-1]=='1') {
q.push({r,c-1});
grid[r][c-1]='0';
};
if(c+1<n && grid[r][c+1]=='1') {
q.push({r,c+1});
grid[r][c+1]='0';
};
}
}
}
}
return num_islands;
}
};