给你一个大小为 m x n 的二进制网格 grid 。网格表示一个地图,其中,0 表示水,1 表示陆地。最初,grid 中的所有单元格都是水单元格(即,所有单元格都是 0)。
可以通过执行 addLand 操作,将某个位置的水转换成陆地。给你一个数组 positions ,其中 positions[i] = [ri, ci] 是要执行第 i 次操作的位置 (ri, ci) 。
返回一个整数数组 answer ,其中 answer[i] 是将单元格 (ri, ci) 转换为陆地后,地图中岛屿的数量。
岛屿 的定义是被「水」包围的「陆地」,通过水平方向或者垂直方向上相邻的陆地连接而成。你可以假设地图网格的四边均被无边无际的「水」所包围。
示例 1:

输入:m = 3, n = 3, positions = [[0,0],[0,1],[1,2],[2,1]]
输出:[1,1,2,3]
解释:
起初,二维网格 grid 被全部注入「水」。(0 代表「水」,1 代表「陆地」)
输入:m = 1, n = 1, positions = [[0,0]]
输出:[1]
提示:
1 <= m, n, positions.length <= 104
1 <= m * n <= 104
positions[i].length == 2
0 <= ri < m
0 <= ci < n
进阶:你可以设计一个时间复杂度 O(k log(mn)) 的算法解决此问题吗?(其中 k == positions.length)
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-islands-ii
方法一:并查集
C++提交内容:
#include
#include
using namespace std;
class UnionFind {
public:
UnionFind(int N) {
for (int i = 0; i < N; ++i) {
parent.push_back(i);
}
count = 0;
}
bool isConnected(int x, int y) {
return find(x) == find(y);
}
int getCount() {
return count;
}
void addCount() {
count++;
}
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
void unionSet(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) {
return;
}
parent[rootX] = rootY;
count--;
}
int getCount() const {
return count;
}
private:
vector<int> parent;
int count;
};
class Solution {
private:
bool inArea(int x, int y, int m, int n) {
return x >= 0 && x < m && y >= 0 && y < n;
}
public:
vector<int> numIslands2(int m, int n, vector<vector<int>> &positions) {
UnionFind unionFind(m * n);
vector<bool> visited;
for (size_t i = 0; i < m * n; i++) {
visited.push_back(false);
}
int DIRECTIONS[4][2] = {{0, 1},
{1, 0},
{0, -1},
{-1, 0}};
vector<int> res;
for (auto &position : positions) {
int currX = position[0];
int currY = position[1];
int index = currX * n + currY;
if (!visited[index]) {
// 把水变成陆地,连通分量个数加 1
unionFind.addCount();
visited[index] = true;
for (auto &direction : DIRECTIONS) {
int newX = currX + direction[0];
int newY = currY + direction[1];
int newIndex = newX * n + newY;
// 下面这三个条件很重要
if (inArea(newX, newY, m, n)
&& visited[newIndex]
&& !unionFind.isConnected(index, newIndex)) {
unionFind.unionSet(index, newIndex);
}
}
}
res.push_back(unionFind.getCount());
}
return res;
}
};