LeetCode解析------803.打砖块-并查集

题目:

我们有一组包含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);
        }
    }
}

在这里插入图片描述

结语:
晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!晚安!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值