LeetCode Solutions
803. Bricks Falling When Hit
Time: $O(mn |\texttt{hits}| \log(mn |\texttt{hits}|))$ Space: $O(mn)$
class UnionFind {
public:
UnionFind(int n) : id(n), size(n, 1) {
iota(begin(id), end(id), 0);
}
void union_(int u, int v) {
const int i = find(u);
const int j = find(v);
if (i == j)
return;
id[i] = j;
size[j] += size[i];
}
int getStableSize() {
// Bricks connected with 0 (top) are stable
return size[find(0)];
}
private:
vector<int> id;
vector<int> size;
int find(int u) {
return id[u] == u ? u : id[u] = find(id[u]);
}
};
class Solution {
public:
vector<int> hitBricks(vector<vector<int>>& grid, vector<vector<int>>& hits) {
m = grid.size();
n = grid[0].size();
UnionFind uf(m * n + 1); // 0 := top (stable)
// Mark cells to hit as 2
for (const vector<int>& hit : hits) {
const int i = hit[0];
const int j = hit[1];
if (grid[i][j] == 1)
grid[i][j] = 2;
}
// Union all 1s
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
if (grid[i][j] == 1)
unionNeighbors(grid, uf, i, j);
vector<int> ans(hits.size());
int stableSize = uf.getStableSize();
for (int i = hits.size() - 1; i >= 0; --i) {
const int x = hits[i][0];
const int y = hits[i][1];
if (grid[x][y] == 2) { // Cells marked from 1 to 2
grid[x][y] = 1; // Unhit, restore back to 1
unionNeighbors(grid, uf, x, y);
const int newStableSize = uf.getStableSize();
if (newStableSize > stableSize)
ans[i] = newStableSize - stableSize - 1; // 1 := the hit cell
stableSize = newStableSize;
}
}
return ans;
}
private:
const vector<int> dirs{0, 1, 0, -1, 0};
int m;
int n;
void unionNeighbors(const vector<vector<int>>& grid, UnionFind& uf, int i,
int j) {
const int hashed = hash(i, j);
for (int k = 0; k < 4; ++k) {
const int x = i + dirs[k];
const int y = j + dirs[k + 1];
if (x < 0 || x == m || y < 0 || y == n)
continue;
if (grid[x][y] != 1)
continue;
uf.union_(hashed, hash(x, y));
}
if (i == 0)
uf.union_(hashed, 0);
}
int hash(int i, int j) {
return i * n + j + 1;
}
};
class UnionFind {
public UnionFind(int n) {
id = new int[n];
size = new int[n];
for (int i = 0; i < n; ++i)
id[i] = i;
Arrays.fill(size, 1);
}
public void union(int u, int v) {
final int i = find(u);
final int j = find(v);
if (i == j)
return;
id[i] = j;
size[j] += size[i];
}
public int getStableSize() {
// Bricks connected with 0 (top) are stable
return size[find(0)];
}
private int[] id;
private int[] size;
private int find(int u) {
return id[u] == u ? u : (id[u] = find(id[u]));
}
}
class Solution {
public int[] hitBricks(int[][] grid, int[][] hits) {
this.m = grid.length;
this.n = grid[0].length;
UnionFind uf = new UnionFind(m * n + 1); // 0 := top (stable)
// Mark cells to hit as 2
for (int[] hit : hits) {
final int i = hit[0];
final int j = hit[1];
if (grid[i][j] == 1)
grid[i][j] = 2;
}
// Union all 1s
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
if (grid[i][j] == 1)
unionNeighbors(grid, uf, i, j);
int[] ans = new int[hits.length];
int stableSize = uf.getStableSize();
for (int i = hits.length - 1; i >= 0; --i) {
final int x = hits[i][0];
final int y = hits[i][1];
if (grid[x][y] == 2) { // Cells marked from 1 to 2
grid[x][y] = 1; // Unhit, restore back to 1
unionNeighbors(grid, uf, x, y);
final int newStableSize = uf.getStableSize();
if (newStableSize > stableSize)
ans[i] = newStableSize - stableSize - 1; // 1 := the hit cell
stableSize = newStableSize;
}
}
return ans;
}
private int m;
private int n;
private static final int[] dirs = {0, 1, 0, -1, 0};
private void unionNeighbors(int[][] grid, UnionFind uf, int i, int j) {
final int hashed = hash(i, j);
for (int k = 0; k < 4; ++k) {
final int x = i + dirs[k];
final int y = j + dirs[k + 1];
if (x < 0 || x == m || y < 0 || y == n)
continue;
if (grid[x][y] != 1)
continue;
uf.union(hashed, hash(x, y));
}
if (i == 0)
uf.union(hashed, 0);
}
private int hash(int i, int j) {
return i * n + j + 1;
}
}