题目地址:
https://leetcode.com/problems/making-a-large-island/
给定一个二维 0 − 1 0-1 0−1矩阵,允许将其中的某一个 0 0 0变为 1 1 1,问能得到的最大的 1 1 1连通块的面积(即 1 1 1的数量)。
并查集。这个问题的关键在于,当遍历到 0 0 0的时候,将其变为 1 1 1之后连通了其的四个邻居,但不知道这四个邻居是属于不同连通块的还是属于相同连通块的,如果属于相同连通块,就会造成重复计算的问题。这时候并查集可以解决这个问题,当两个节点在并查集的树的祖宗节点相等,就说明它们是属于同一个连通块的。代码如下:
class Solution {
public:
using PII = pair<int, int>;
vector<int> p, sz;
int largestIsland(vector<vector<int>>& g) {
int m = g.size(), n = g[0].size(), mn = m * n;
p.resize(mn);
sz.resize(mn);
for (int i = 0; i < mn; i++) p[i] = i, sz[i] = 1;
auto f = [&](int x, int y) { return x * n + y; };
auto merge = [&](int x, int y) {
int px = find(x), py = find(y);
if (px == py) return;
p[px] = py, sz[py] += sz[px];
};
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
if (!g[i][j]) continue;
int x = f(i, j);
for (auto& pp :
vector<PII>{{i - 1, j}, {i + 1, j}, {i, j - 1}, {i, j + 1}}) {
auto& [nx, ny] = pp;
if (0 <= nx && nx < m && 0 <= ny && ny < n && g[nx][ny] == 1)
merge(x, f(nx, ny));
}
}
int res = 0;
unordered_map<int, int> mp;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
int x = f(i, j);
if (g[i][j]) {
res = max(res, sz[x]);
continue;
}
mp.clear();
for (auto& pp :
vector<PII>{{i - 1, j}, {i + 1, j}, {i, j - 1}, {i, j + 1}}) {
auto& [nx, ny] = pp;
if (0 <= nx && nx < m && 0 <= ny && ny < n && g[nx][ny] == 1) {
int pa = find(f(nx, ny));
mp[pa] = sz[pa];
}
}
int cnt = 1;
for (auto& [k, v] : mp) cnt += v;
res = max(res, cnt);
}
return res;
}
int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
};
时间复杂度 O ( m n log ∗ ( m n ) ) O(mn\log ^* (mn)) O(mnlog∗(mn)),空间 O ( m n ) O(mn) O(mn)。