题目

有一个 m x n 的二元网格,其中 1 表示砖块,0 表示空白。砖块 稳定(不会掉落)的前提是:

一块砖直接连接到网格的顶部,或者
至少有一块相邻(4 个方向之一)砖块 稳定 不会掉落时
给你一个数组 hits ,这是需要依次消除砖块的位置。每当消除 hits[i] = (rowi, coli) 位置上的砖块时,对应位置的砖块(若存在)会消失,然后其他的砖块可能因为这一消除操作而掉落。一旦砖块掉落,它会立即从网格中消失(即,它不会落在其他稳定的砖块上)。

返回一个数组 result ,其中 result[i] 表示第 i 次消除操作对应掉落的砖块数目。

样例

输入: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] 。

并查集

消除一个砖块的效果是:一个连通分量被分成了两个连通分量;
并查集的作用是:把两个连通分量合并成一个连通分量。
提示我们这个问题需要 反向 思考。即考虑:补上被击碎的砖块以后,有多少个砖块因为这个补上的这个砖块而与屋顶的砖块相连。每一次击碎一个砖块,因击碎砖块而消失的砖块只会越来越少。因此可以按照数组 hits 的顺序 逆序地 把这些砖块依次补上。如图所示:

当最后一块砖块补上的时候,就恰好可以恢复成刚开始的时候整个二维表格的样子。

作者:LeetCode
链接:https://leetcode-cn.com/problems/bricks-falling-when-hit/solution/803-da-zhuan-kuai-by-leetcode-r5kf/

class Solution {int cols;int rows;private final int[][] DIRECTIONS = {{0,1},{1,0},{-1,0},{0,-1}};public int[] hitBricks(int[][] grid, int[][] hits) {this.cols = grid[0].length;this.rows = grid.length;int[][] copy = new int[rows][cols];int size = rows * cols;UnionFind un = new UnionFind(size + 1);// 原数组copyfor(int i = 0;i < rows;i++){for(int j = 0;j < cols;j++){copy[i][j] = grid[i][j];}}for(int[] hit : hits){int x = hit[0];int y = hit[1];copy[x][y] = 0;}for(int i = 0; i < cols; i++){if(copy[0][i] == 1){un.union(i,size);}}for(int i = 1; i < rows; i++){for(int j = 0; j < cols; j++){if(copy[i][j] == 1){// 保证上方也是方块if(copy[i - 1][j] == 1){un.union(getIndex(i,j),getIndex(i - 1,j));}// 如果左边是方块if(j > 0 && copy[i][j - 1] == 1){un.union(getIndex(i,j),getIndex(i,j - 1));}}}}int[] res = new int[hits.length];for(int i = hits.length - 1; i >= 0; i--){int x = hits[i][0];int y = hits[i][1];if(grid[x][y] == 0){continue;}// 补回之前的int origin = un.getSize(size);// 如果是顶层if(x == 0){un.union(y,size);}for(int[] direction : DIRECTIONS){int newX = x + direction[0];int newY = y + direction[1];if(inGraph(newX,newY) && copy[newX][newY] == 1){un.union(getIndex(newX,newY),getIndex(x,y));}}// 得到现在的int current = un.getSize(size);res[i] = Math.max(0,current - origin - 1);// 补上砖块copy[x][y] = 1;}return res;}// 判断是否在图中public boolean inGraph(int i,int j){if(i < 0 || j < 0 || i >= rows || j >= cols){return false;}return true;}// 得到二维数组转为一维数组位置public int getIndex(int i,int j){return i * cols + j;}private class UnionFind{int size;int f[];int rank[];public UnionFind(int size){this.size = size;f = new int[size];rank = new int[size];Arrays.fill(rank,1);for(int i = 0;i < size;i++){f[i] = i;}}public int find(int x){return f[x] = f[x] == x ? x : find(f[x]);}public void union(int u,int v){u = find(u);v = find(v);if(u == v){return;}if(rank[u] < rank[v]){int temp = u;u = v;v = temp;}rank[u] += rank[v];f[v] = u;}public int getSize(int x){x = find(x);return rank[x];}}
}

并查集leetcode经典逆序思维相关推荐

  1. 通用版!完整代码,单链表SingleLinkedList增删改查,反转,逆序,有效数据等Java实现

    文章目录 节点类 链表类(主要) 测试类 小结 节点类 可以根据需要,对节点属性进行修改.注意重写toString()方法,以便后续的输出操作. //节点类 class Node {public in ...

  2. codeforces1303 F. Number of Components(并查集+添_正序、删_逆序)

    F. Number of Components 并查集,每次修改考虑的是这个修改带来的贡献,就是和相邻颜色的对比,如果不考虑先不考虑颜色覆盖,那么添加颜色首先会产生一个新的连通块,然后考虑合并,每合并 ...

  3. LeetCode 1265. 逆序打印不可变链表(递归)

    文章目录 1. 题目 2. 解题 1. 题目 给您一个不可变的链表,使用下列接口逆序打印每个节点的值: ImmutableListNode: 描述不可变链表的接口,链表的头节点已给出. 您需要使用以下 ...

  4. 并查集leetcode.1697

    public boolean[] distanceLimitedPathsExist(int n, int[][] edgeList, int[][] queries) {Arrays.sort(ed ...

  5. 分门别类刷leetcode——高级数据结构(字典树,前缀树,trie树,并查集,线段树)

    目录 Trie树(字典树.前缀树)的基础知识 字典树的节点表示 字典树构造的例子 字典树的前序遍历 获取字典树中全部单词 字典树的整体功能 字典树的插入操作 字典树的搜索操作 字典树的前缀查询 字典树 ...

  6. POJ 并查集 题目汇总 ——czyuan原创(转)

    继续数据结构的复习,本次的专题是:并查集. 并查集,顾名思义,干的就是"并"和"查"两件事.很多与集合相关的操作都可以用并查集高效的解决. 两个操作代码:    ...

  7. 2021年SWPUACM暑假集训day2并查集算法

    什么是并查集 并查集是一种树形的数据结构,顾名思义,它用于处理一些不交集的 合并 及 查询 问题. 它支持两种操作: 1.查找(find):确定某个元素处于哪个子集 2.合并(merge):将两个子集 ...

  8. 银河英雄传说 ← 带权并查集

    [问题描述] 有一个划分为N列的星际战场,各列依次编号为1,2,-,N. 有N艘战舰,也依次编号为1,2,-,N,其中第i号战舰处于第i列. 有T条指令,每条指令格式为以下两种之一: 1.M i j, ...

  9. BZOJ 1015 [JSOI2008]星球大战starwar (逆序并查集)

    BZOJ 1015 思路:并查集只有联边的作用,无法做到拆边,因此采取逆序做法.先将边拆掉,再用并查集进行联边,不同联通块相连则联通块数目减一. 1 #include<bits/stdc++.h ...

最新文章

  1. java 生成器 设计模式_Java中的生成器设计模式
  2. python中函数定义_Python中函数的定义与使用
  3. 智能终端会议系统(20)---网络视频传输协议--RTP/RTCP/RTSP/SIP/SDP 之间关系
  4. 修改 “嗨加游-Prefix.pch” 或者 “嗨加游-Info.plist ” 方法
  5. 查oracle执行的sql,oracle查询正在执行的sql
  6. dos从优盘启动计算机,DOS启动版U盘制作方法(usbboot)
  7. 计算机网络物理层之数据通信的基础知识
  8. STL标准模版库--vector的操作集合
  9. CSS行高line-height属性理解及应用
  10. 【蓝桥杯国赛真题24】Scratch货物运输 第十三届蓝桥杯 图形化编程scratch国赛真题和答案讲解
  11. 数据结构 图论02 十字链表详解 代码
  12. 交叉编译工具链的安装和配置过程
  13. 分布式定时任务调度框架
  14. 并行强化学习算法:A2C/A3C
  15. 一文了解CSP、NOIP、NOI 三大信息学赛事
  16. Windows或Linux中32位与64位操作系统的区别
  17. 免流混淆 一 待完善(更新中)
  18. cpptraj对于轨迹的浓缩
  19. 科学计算基础软件包Numpy学习 02
  20. signal 11 linux,关于运行时Signal 11 Caught的错误

热门文章

  1. detached entity passed to persist:***
  2. 数据库的逻辑结构设计步骤
  3. 说一下公平锁和非公平锁的区别?
  4. 社会负面事件多《王者荣耀》们是否该被“分级”
  5. MySQL导出数据为csv的方法(亲测),导出数据为各种文件类型
  6. 大班下学期家长会发言稿
  7. Python实现网络通信中的套接字(Socket)
  8. 2019.2.27热身赛
  9. 逐行扫描和隔行扫描的区别,原理
  10. ajax导致csrf验证失败的解决方法