12、岛屿数量
题目
12.0、广度优先遍历
从一个点开始,进行广播一样的遍历,比如示例1,发现第一个数是一个岛,那么从【0,0】开始广播,广播依次经过
【0,1】,【1,0】
【0,2】,【1,1】,【2,0】
【0,3】,【2,1】
【1,3】
每到一个地方,就把那个坐标对应的位置变为0
使用队列或者栈来存储下次广播到达的坐标
int numIslands0(vector<vector<char>>& grid)
{
stack <pair<int, int>> data;
int rows = grid.size();
int cols = grid[0].size();
int result = 0;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (grid[i][j] == '1')
{
result++;
data.push({ i,j });
while (!data.empty())
{
pair<int, int> nowLocation = data.top();
data.pop();
grid[nowLocation.first][nowLocation.second] = '0';
if (nowLocation.first + 1 < rows && grid[nowLocation.first + 1][nowLocation.second] == '1')data.push({ nowLocation.first + 1,nowLocation.second });
if (nowLocation.second + 1 < cols && grid[nowLocation.first][nowLocation.second + 1] == '1')data.push({ nowLocation.first,nowLocation.second + 1 });
if (nowLocation.first - 1 >= 0 && grid[nowLocation.first - 1][nowLocation.second] == '1')data.push({ nowLocation.first - 1,nowLocation.second });
if (nowLocation.second - 1 >= 0 && grid[nowLocation.first][nowLocation.second - 1] == '1')data.push({ nowLocation.first,nowLocation.second - 1 });
}
}
}
}
return result;
}
-
时间复杂度:O(m n)m为行数,n为列数
-
空间复杂度:O(min(m n))下次广播坐标最大就是个正方形的对角线
12.1、深度优先搜索
和广度不一样的是,广度是以广播形式一圈一圈向外展开,而深度是从一个方向一直进行到底,比如示例1
- 先一直向右走到【0,3】
- 向下走一格到【1,3】
- 原路返回至【0,1】
- 向下走到【2,1】
- 想左走一格到【2,0】
- 向上走一格到【1,0】
- 原路返回至【0,1】
- 回到【0,0】
没到一个地方,就把该坐标对应的值变为0
void deepSearch1(vector<vector<char>>& grid, int rowNum, int colNum)
{
grid[rowNum][colNum] = '0';
if (rowNum + 1 < grid.size() && grid[rowNum + 1][colNum] == '1')deepSearch(grid, rowNum + 1, colNum);
if (colNum + 1 < grid[0].size() && grid[rowNum][colNum + 1] == '1')deepSearch(grid, rowNum, colNum + 1);
if (rowNum - 1 >= 0 && grid[rowNum - 1][colNum] == '1')deepSearch(grid, rowNum - 1, colNum);
if (colNum - 1 >= 0 && grid[rowNum][colNum - 1] == '1')deepSearch(grid, rowNum, colNum - 1);
}
int numIslands2(vector<vector<char>>& grid)
{
int rows = grid.size();
int cols = grid[0].size();
int result = 0;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (grid[i][j] == '1')
{
result++;
deepSearch(grid, i, j);
}
}
}
return result;
}
-
时间复杂度:O(m n)m为行数,n为列数
-
空间复杂度:O(m n)最坏情况是m n,就是全都是岛最初的一条道走到黑,直到走完。
12.2、并查集(重点)
这个博主也是刚学,害怕误导,有兴趣的可以去网上找一下资料,这里仅仅放代码。
class UnionFind
{
private:
vector<int> parent;
vector<int> rank;
int count = 0;
//查找父节点
int find(int i)
{
return parent[i] == i ? i : (parent[i] = find(parent[i]));
}
public:
UnionFind(vector<vector<char>>& grid)
{
int rows = grid.size();
int cols = grid[0].size();
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (grid[i][j] == '1')
{
parent.push_back(i * cols + j);
count++;
}
else
parent.push_back(-1);
rank.push_back(0);
}
}
}
//按秩合并
void merge(int x, int y)
{
int rootx = find(x);
int rooty = find(y);
if (rootx != rooty)
{
if (rank[rootx] <= rank[rooty])
parent[rootx] = rooty;
else
parent[rooty] = rootx;
if (rank[rootx] == rank[rooty])rank[rootx]++;
count--;
}
}
//返回集合个数
int getCount()
{
return count;
}
};
//并查集
int numIslands2(vector<vector<char>>& grid)
{
int rows = grid.size();
int cols = grid[0].size();
UnionFind unionFind(grid);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (grid[i][j] == '1')
{
grid[i][j] = '0';
if (i + 1 < rows && grid[i + 1][j] == '1')unionFind.merge(i * cols + j, (i + 1) * cols + j);
if (j + 1 < cols && grid[i][j + 1] == '1')unionFind.merge(i * cols + j, i * cols + j + 1);
}
}
}
return unionFind.getCount();
}
-
时间复杂度:O(m n)其实还应该乘以每次的find时间,但由于是常量(不大于5),所以忽略
-
空间复杂度:O(m n)并查集需要储存一个parent和一个rank