题目:
我们有一组包含1和0的网格;其中1表示砖块。 当且仅当一块砖直接连接到网格的顶部,或者它至少有一块相邻(4 个方向之一)砖块不会掉落时,它才不会落下。
我们会依次消除一些砖块。每当我们消除 (i, j) 位置时, 对应位置的砖块(若存在)会消失,然后其他的砖块可能因为这个消除而落下。
返回一个数组表示每次消除操作对应落下的砖块数目。
示例 1:
输入: grid = [[1,0,0,0],[1,1,1,0]] hits = [[1,0]]
输出: [2]
解释: 如果我们消除(1,0)位置的砖块, 在(1, 1) 和(1, 2) 的砖块会落下。所以我们应该返回2。
示例 2:
输入: grid = [[1,0,0,0],[1,1,0,0]] hits = [[1,1],[1,0]]
输出:[0,0]
解释:当我们消除(1, 0)的砖块时,(1, 1)的砖块已经由于上一步消除而消失了。所以每次消除操作不会造成砖块落下。注意(1,0)砖块不会记作落下的砖块。
注意:
网格的行数和列数的范围是[1, 200]。
消除的数字不会超过网格的区域。 可以保证每次的消除都不相同,并且位于网格的内部。
一个消除的位置可能没有砖块,如果这样的话,就不会有砖块落下。
简单介绍:
题目:打砖块
题目难度:困难
使用语言:JAVA。
这道题来自leetcode题库的并查集标签。
解题思路:
首先看题、分析题意,我们可以明确1个关键点:
1.用什么方式去统计每次击打砖块,伴随这次击打掉落的砖块数
既然,我们已经分析出来题目的关键任务了,下面我们就可以开始思考实现了。
我们采用算法与数据结构的思路来剖析一下这题,
数据结构:
要实现对数据的操作,我们要先明确存储数据的数据结构。
该题的数据结构的作用:
1.采用HashSet的nowRemain变量统计当前不掉落砖块的信息
算法:
既然明确了我们的数据结构,我们就可以开始我们的算法分析了。
1.第一步,击打砖块。将击打位置对应的砖块减1,因为可能同一位置会击打多次。
2.第二步,恢复顶层相关砖块。恢复与顶层直接、间接连接的砖块(敲击不会造成这些砖块的掉落)
3.第三步,恢复其他砖块。从最后一步hit开始,逐渐恢复砖块。同时,找回因为hit掉落的砖块,并加入remain中
代码部分:
public class Solution {
public int[] hitBricks(int[][] grid, int[][] hits) {
HashSet<String> nowRemain=new HashSet<>();//当前状态不掉落砖块
int hitSize=hits.length;//击打次数
int[] res=new int[hitSize];//结果数组
int rowSize=grid.length,colSize=grid[0].length;//网格的行与列
if(grid.length==0||grid[0].length==0) return res;
//第一步,击打砖块
for(int i=0;i<hitSize;i++){
grid[hits[i][0]][hits[i][1]]--;
}
//第二步,恢复与顶层直接、间接连接的砖块(敲击不会造成这些砖块的掉落)
for(int i=0;i<colSize;i++){
if(grid[0][i]==1){
findRemain(grid,0,i,nowRemain);//恢复砖块
}
}
//第三步,从最后一步hit开始,逐渐恢复砖块。同时,找回因为hit掉落的砖块,并加入remain中
for(int i=hitSize-1;i>=0;i--){
int row=hits[i][0],col=hits[i][1];//击打的位置
grid[row][col]+=1;//恢复砖块
//恢复到砖块存在
if(grid[row][col]==1){
int afterHitRemainSize=nowRemain.size();//恢复之前的砖块数
//顶部的砖块或者有相邻砖块存在,则该砖块可以固定。
//如果砖块不能固定,说明该砖块是之前hit砖块掉落的,不是因为hit这块砖掉落的。
if(row==0||(row>0&&nowRemain.contains((row-1)+":"+col))||(row<rowSize-1&&nowRemain.contains((row+1)+":"+col))
||(col>0&&nowRemain.contains(row+":"+(col-1)))||(col<colSize-1&&nowRemain.contains(row+":"+(col+1)))){
findRemain(grid,row,col,nowRemain);
res[i]=nowRemain.size()-afterHitRemainSize-1;//掉落的砖块
}
}
}
return res;
}
//恢复grid[row][col]结点附近(上下左右)的砖块
public void findRemain(int[][] grid, int row, int col, HashSet<String> nowRemain){
int rowSize=grid.length,colSize=grid[0].length;
//如果不是砖块或者已经恢复过该砖块
if(grid[row][col]!=1||nowRemain.contains(row+":"+col)){
return;
}
//恢复砖块
nowRemain.add(row+":"+col);
//上方
if(row>0){
findRemain(grid,row-1,col,nowRemain);
}
//下方
if(row<rowSize-1){
findRemain(grid,row+1,col,nowRemain);
}
//左方
if(col>0){
findRemain(grid,row,col-1,nowRemain);
}
//右方
if(col<colSize-1){
findRemain(grid,row,col+1,nowRemain);
}
}
}
结语:
晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!