面试题16.19. 水域大小
其实dfs更好写,但为了练并查集。
需要注意的是这道题并非朴素的并查集,而是需要维护每一簇节点的数量,而且这个数量的值仅在根节点是有意义的,其他非根节点因为没有额外维护(也不需要)是没有意义的。
class Solution {
public:
int fa[1000 * 1000];
int cnt[1000 * 1000];
int dirs[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
int getId(int i, int j, int n){
return i * n + j;
}
void init(int size){
for(int i = 0; i < size; ++i){
fa[i] = i;
cnt[i] = 1;
}
}
int find(int x){
return fa[x] == x ? x : (fa[x] = find(fa[x]));
}
void merge(int x, int y){
int x_fa = find(x), y_fa = find(y);
fa[x_fa] = y_fa;
cnt[y_fa] += cnt[x_fa];
}
vector<int> pondSizes(vector<vector<int>>& land) {
int m = land.size(), n = land[0].size();
init(m * n);
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
if(land[i][j] == 0){
for(auto& dir : dirs){
int nx = i + dir[0], ny = j + dir[1];
if(nx < 0 || nx >= m || ny < 0 || ny >= n || land[nx][ny] != 0) continue;
if(find(getId(i, j, n)) != find(getId(nx, ny, n)))
merge(getId(i, j, n), getId(nx, ny, n));
}
}
}
}
vector<int> ans;
for(int i = 0; i < m; ++i){
for(int j = 0; j < n; ++j){
if(land[i][j] == 0 && find(getId(i, j, n)) == getId(i, j, n)){
ans.push_back(cnt[getId(i, j, n)]);
}
}
}
sort(ans.begin(), ans.end());
return ans;
}
};