有一个 m x n 的二元网格,其中 1 表示砖块,0 表示空白。砖块 稳定(不会掉落)的前提是:
一块砖直接连接到网格的顶部,或者
至少有一块相邻(4 个方向之一)砖块 稳定 不会掉落时
给你一个数组 hits ,这是需要依次消除砖块的位置。每当消除 hits[i] = (rowi, coli) 位置上的砖块时,对应位置的砖块(若存在)会消失,然后其他的砖块可能因为这一消除操作而掉落。一旦砖块掉落,它会立即从网格中消失(即,它不会落在其他稳定的砖块上)。返回一个数组 result ,其中 result[i] 表示第 i 次消除操作对应掉落的砖块数目。
注意,消除可能指向是没有砖块的空白位置,如果发生这种情况,则没有砖块掉落。
示例 1:
输入:grid = [[1,0,0,0],[1,1,1,0]], hits = [[1,0]]
输出:[2]
解释:
网格开始为:
[[1,0,0,0],
[1,1,1,0]]
消除 (1,0) 处加粗的砖块,得到网格:
[[1,0,0,0]
[0,1,1,0]]
两个加粗的砖不再稳定,因为它们不再与顶部相连,也不再与另一个稳定的砖相邻,因此它们将掉落。得到网格:
[[1,0,0,0],
[0,0,0,0]]
因此,结果为 [2] 。
示例 2:
输入:grid = [[1,0,0,0],[1,1,0,0]], hits = [[1,1],[1,0]]
输出:[0,0]
解释:
网格开始为:
[[1,0,0,0],
[1,1,0,0]]
消除 (1,1) 处加粗的砖块,得到网格:
[[1,0,0,0],
[1,0,0,0]]
剩下的砖都很稳定,所以不会掉落。网格保持不变:
[[1,0,0,0],
[1,0,0,0]]
接下来消除 (1,0) 处加粗的砖块,得到网格:
[[1,0,0,0],
[0,0,0,0]]
剩下的砖块仍然是稳定的,所以不会有砖块掉落。
因此,结果为 [0,0] 。
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 200
grid[i][j] 为 0 或 1
1 <= hits.length <= 4 * 104
hits[i].length == 2
0 <= xi <= m - 1
0 <= yi <= n - 1
所有 (xi, yi) 互不相同
基本思路:问题等价于,当敲碎某个节点时,连通域情况发生变化,如果,连通域一分为二的话,那么不在与顶层相连的直接消失;连通域的问题一般容易想到并查集,但是并查集擅长合并,并不擅长拆分连通域,又因为[xi,yi]不会重复,故可以逆向思维,将问题转换成,逆序填充被敲碎的点,如果可以与顶层相连,那么增加的节点数就是所求结果。
vector<int> parent,psize;
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
void init(int n){
parent.resize(n,0);
psize.resize(n,1);
for(int i=0;i<n;i++){
parent[i]=i;
}
}
int find(int x){
if(x!=parent[x]){
parent[x]=find(parent[x]);
}
return parent[x];
}
void connect(int x,int y){
int rootx=find(x);
int rooty=find(y);
if(rootx==rooty)
return;
if(psize[rootx]>psize[rooty]){
parent[rooty]=rootx;
psize[rootx]+=psize[rooty];
}
else{
parent[rootx]=rooty;
psize[rooty]+=psize[rootx];
}
}
int getSize(int x){
return psize[find(x)];
}
vector<int> hitBricks(vector<vector<int>>& grid, vector<vector<int>>& hits) {
auto copyGrid=grid;
for(auto &vec:hits){
copyGrid[vec[0]][vec[1]]=0;
}
int h=grid.size(),w=grid[0].size();
init(h*w+1);
for(int i=0;i<h;i++){ //初始化copyGrid
for(int j=0;j<w;j++){
if(copyGrid[i][j]){
if(i==0){
connect(h*w,j);
}
if(i>0&©Grid[i-1][j]){
connect(i*w+j,(i-1)*w+j);
}
if(j>0&©Grid[i][j-1]){
connect(i*w+j,i*w+j-1);
}
}
}
}
vector<int> res(hits.size(),0);
for(int i=hits.size()-1;i>=0;i--){
int x=hits[i][0];
int y=hits[i][1];
if(grid[x][y]==0)
continue;
int pre=getSize(h*w); //连在天花板上的数目
if(x==0)
connect(h*w,y);
for(int j=0;j<4;j++){
int newx=x+dx[j];
int newy=y+dy[j];
if(newx>=0&&newx<h&&newy>=0&&newy<w&©Grid[newx][newy]){
connect(x*w+y,newx*w+newy);
}
}
int cur=getSize(h*w);
res[i]=max(0,cur-pre-1);
copyGrid[x][y]=1;
}
return res;
}
基本思路:dfs,超时
int dx[4] = { 0,0,-1,1 };
int dy[4] = { -1,1,0,0 };
int h, w;
vector<int> dfs(int x, int y, vector<vector<int>> &grid, vector<vector<bool>> &isvisited, vector<vector<int>> &rect) {
if (x == 0) {
return { 0,1 };
}
int cnt = 1;
isvisited[x][y] = true;
rect.push_back({ x,y });
for (int i = 0; i < 4; i++) {
int newx = x + dx[i];
int newy = y + dy[i];
if (newx >= 0 && newx < h&&newy >= 0 && newy < w&&grid[newx][newy] && !isvisited[newx][newy]) {
auto tmp = dfs(newx, newy, grid, isvisited,rect);
if (tmp[1])
return { 0,1 };
else {
cnt += tmp[0];
}
}
}
isvisited[x][y] = true;
return { cnt,0 };
}
vector<int> hitBricks(vector<vector<int>>& grid, vector<vector<int>>& hits) {
vector<int> res;
h = grid.size();
w = grid[0].size();
for (auto &p : hits) {
int x = p[0];
int y = p[1];
if (grid[x][y] == 0) {
res.emplace_back(0);
continue;
}
int cnt = 0;
vector<vector<bool>> isvisited(h, vector<bool>(w, false));
isvisited[x][y] = true;
for (int i = 0; i < 4; i++) {
int newx = x + dx[i];
int newy = y + dy[i];
vector<vector<int>> rect; //记录路径
vector<vector<bool>> isvisited(h, vector<bool>(w, false)); //是否参观过
isvisited[x][y] = true;
if (newx >= 0 && newx < h&&newy >= 0 && newy < w&&grid[newx][newy]) {
auto tmp = dfs(newx, newy, grid, isvisited,rect); //[len,bool],分别记录长度和是否与顶层相连
if (!tmp[1]) {
cnt += tmp[0];
for (auto &r : rect) { //如果没有和顶层相连,除掉
grid[r[0]][r[1]] = 0;
}
}
}
}
res.emplace_back(cnt);
grid[x][y] = 0;
}
return res;
}