LeetCode200.岛屿数量
这是一道求连通块个数的题,是一道dfs模板题。
DFS
class Solution {
public:
int m,n;//m行n列
bool board(int x,int y)
{
if((x>=0)&&(y>=0)&&(x<n)&&(y<m))
{
return true;
}
else return false;
}
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int dfs(vector<vector<char>> &grid,int y,int x)
{
grid[y][x]='0';
for(int i=0;i<4;i++)
{
int tx=x+dx[i];
int ty=y+dy[i];
if(board(tx,ty)&&grid[ty][tx]=='1')
{
dfs(grid,ty,tx);
}
}
return 1;
}
int numIslands(vector<vector<char>>& grid) {
m=grid.size();
n=grid[0].size();
int num=0;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(grid[i][j]=='1')
{
dfs(grid,i,j);
num++;
}
}
}
return num;
}
};
dfs每次搜索完一个连通块就感染使
grid[y][x]='0'
,一次搜索感染一个连通块,最终dfs的次数就是连通块的数量。
注意边界情况,因为vector按行优先存储,所以应该用grid[y][x]
避免下标越界。
时间复杂度:O(mn)
BFS
class Solution {
public:
typedef pair<int ,int>P;
int m,n;//m行n列
bool board(int x,int y)
{
if((x>=0)&&(y>=0)&&(x<n)&&(y<m))
{
return true;
}
else return false;
}
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int bfs(vector<vector<char>>& grid,int y,int x)
{
grid[y][x]='0';
queue<P> que;
que.push(P(y,x));
while (que.size())
{
P p=que.front();
que.pop();
for (int i = 0; i < 4; i++)
{
int nx=p.second+dx[i],ny=p.first+dy[i];
if(board(nx,ny)&&grid[ny][nx]!='0')
{
grid[ny][nx]='0';
que.push(P(ny,nx));
}
}
}
return 1;
}
int numIslands(vector<vector<char>>& grid) {
m=grid.size();
n=grid[0].size();
int num=0;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(grid[i][j]=='1')
{
bfs(grid,i,j);
num++;
}
}
}
return num;
}
};
这道题显然也可以用BFS做,DFS通过递归利用栈进行遍历,而BFS利用队列进行搜索感染,每次将走过的路径都感染,连通块的个数就是BFS的次数。
同样,注意避免数组下标越界的问题。
时间复杂度:O(mn)
并查集
class Solution {
public:
int m,n;//m行n列
vector<int> a;
vector<int> h;
int num=0;
void unionserch(vector<vector<char>>& grid)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(grid[i][j]=='1')
{
a.push_back(i*n+j);
num++;
}
else
{
a.push_back(-1);
}
h.push_back(0);
}
}
}
int find(int x)
{
return x==a[x] ? x : a[x]=find(a[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y) return ;
if(h[x]<h[y])
{
a[x]=y;
}
else
{
a[y]=x;
if(h[x]==h[y]) h[x]++;
}
num--;
}
bool board(int x,int y)
{
if((x>=0)&&(y>=0)&&(x<n)&&(y<m))
{
return true;
}
else return false;
}
int dx[2]={0,1};
int dy[2]={1,0};
int numIslands(vector<vector<char>>& grid) {
m=grid.size();
n=grid[0].size();
unionserch(grid);
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(grid[i][j]=='1')
{
grid[i][j]='0';
for(int k=0;k<2;k++)
{
int tx=j+dx[k];
int ty=i+dy[k];
if(board(tx,ty)&&grid[ty][tx]=='1')
{
unite(i*n+j,ty*n+tx);
}
}
}
}
}
return num;
}
};
由于参数是二维vector,所以初始化时利用按行优先存储的位置
i*n+j
来标识元素在数组中唯一的位置,初始化时利用num
模拟连通块的个数。
unite()函数每次执行,只要两个结点不属于同一连通分支就合并并执行num--
代表减少一个连通块。
最终本来的-合并的=剩下的
连通块数量。
时间复杂度:O(mn×α(mn))