803. Bricks Falling When Hit
https://leetcode.com/problems/bricks-falling-when-hit/
由0和1组成的矩阵,每次给定一个1敲掉,把敲掉后不与首行的1相连通的1一并都抹除。问每次敲一共会抹除多少元素。查与之连通的元素用union find。union find适合将两个component连起来,这里却需要把连起来的拆开,并查集并无法快速支持这样的操作,要尽量把敲掉替换成并查集擅长的union操作。因此把敲掉看作倒着的补齐操作,每次补上元素后新增加与首行1相连的元素即敲掉元素所失去的元素。并查集还有个常用的小优化,即生成一个dummy src连接所有的首行1形成一个大component,这样只需要查一次src的size就知道所有与首行1连通的元素数目。
/*
* @lc app=leetcode id=803 lang=cpp
*
* [803] Bricks Falling When Hit
*
* https://leetcode.com/problems/bricks-falling-when-hit/description/
*
* algorithms
* Hard (29.14%)
* Likes: 333
* Dislikes: 96
* Total Accepted: 11.6K
* Total Submissions: 39.6K
* Testcase Example: '[[1,0,0,0],[1,1,1,0]]\n[[1,0]]'
*
* We have a grid of 1s and 0s; the 1s in a cell represent bricks. A brick
* will not drop if and only if it is directly connected to the top of the
* grid, or at least one of its (4-way) adjacent bricks will not drop.
*
* We will do some erasures sequentially. Each time we want to do the erasure
* at the location (i, j), the brick (if it exists) on that location will
* disappear, and then some other bricks may drop because of that erasure.
*
* Return an array representing the number of bricks that will drop after each
* erasure in sequence.
*
*
* Example 1:
* Input:
* grid = [[1,0,0,0],[1,1,1,0]]
* hits = [[1,0]]
* Output: [2]
* Explanation:
* If we erase the brick at (1, 0), the brick at (1, 1) and (1, 2) will drop.
* So we should return 2.
*
*
* Example 2:
* Input:
* grid = [[1,0,0,0],[1,1,0,0]]
* hits = [[1,1],[1,0]]
* Output: [0,0]
* Explanation:
* When we erase the brick at (1, 0), the brick at (1, 1) has already
* disappeared due to the last move. So each erasure will cause no bricks
* dropping. Note that the erased brick (1, 0) will not be counted as a
* dropped brick.
*
*
*
* Note:
*
*
* The number of rows and columns in the grid will be in the range [1,
* 200].
* The number of erasures will not exceed the area of the grid.
* It is guaranteed that each erasure will be different from any other erasure,
* and located inside the grid.
* An erasure may refer to a location with no brick - if it does, no bricks
* drop.
*
*
*/
class Solution {
public:
class UF {
vector<int> *parents;
vector<int> *sizes;
public:
UF(const int N) {
parents = new vector<int>(N);
sizes = new vector<int>(N, 1);
for (int i = 0; i < N; ++i) {
(*parents)[i] = i;
}
}
int find(int x) {
if ((*parents)[x] != x) (*parents)[x] = find((*parents)[x]);
return (*parents)[x];
}
void un(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return;
(*parents)[y] = x;
(*sizes)[x] += (*sizes)[y];
}
int size(int x) {
return (*sizes)[find(x)];
}
};
vector<int> hitBricks(vector<vector<int>>& grid, vector<vector<int>>& hits) {
const int M = grid.size(), N = grid[0].size(), K = hits.size();
vector<vector<int>> dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
for (const auto &h : hits) {
if (grid[h[0]][h[1]] == 1) grid[h[0]][h[1]] = 2;
}
UF uf(M * N + 1);
const auto union_around = [&](const int i, const int j) {
for (const auto &dir : dirs) {
const int x = i + dir[0];
const int y = j + dir[1];
if (x >= 0 && x < M && y >= 0 && y < N && grid[x][y] == 1) {
uf.un(i * N + j + 1, x * N + y + 1);
}
}
if (i == 0) uf.un(0, i * N + j + 1);
};
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
if (grid[i][j] != 1) continue;
union_around(i, j);
}
}
vector<int> res(K);
int left = uf.size(0);
for (int i = K - 1; i >= 0; --i) {
const int x = hits[i][0], y = hits[i][1];
if (grid[x][y] == 2) {
grid[x][y] = 1;
union_around(x, y);
const int new_left = uf.size(0);
res[i] = max(new_left - left - 1, 0);
left = new_left;
}
}
return res;
}
};
Last updated
Was this helpful?