package class13; // 本题测试链接 : https://leetcode.com/problems/bricks-falling-when-hit/ public class Code04_BricksFallingWhenHit { public static int[] hitBricks(int[][] grid, int[][] hits) { for (int i = 0; i < hits.length; i++) { if (grid[hits[i][0]][hits[i][1]] == 1) { grid[hits[i][0]][hits[i][1]] = 2; } } UnionFind unionFind = new UnionFind(grid); int[] ans = new int[hits.length]; for (int i = hits.length - 1; i >= 0; i--) { if (grid[hits[i][0]][hits[i][1]] == 2) { ans[i] = unionFind.finger(hits[i][0], hits[i][1]); } } return ans; } // 并查集 public static class UnionFind { private int N; private int M; // 有多少块砖,连到了天花板上 private int cellingAll; // 原始矩阵,因为炮弹的影响,1 -> 2 private int[][] grid; // cellingSet[i] = true; i 是头节点,所在的集合是天花板集合 private boolean[] cellingSet; private int[] fatherMap; private int[] sizeMap; private int[] stack; public UnionFind(int[][] matrix) { initSpace(matrix); initConnect(); } private void initSpace(int[][] matrix) { grid = matrix; N = grid.length; M = grid[0].length; int all = N * M; cellingAll = 0; cellingSet = new boolean[all]; fatherMap = new int[all]; sizeMap = new int[all]; stack = new int[all]; for (int row = 0; row < N; row++) { for (int col = 0; col < M; col++) { if (grid[row][col] == 1) { int index = row * M + col; fatherMap[index] = index; sizeMap[index] = 1; if (row == 0) { cellingSet[index] = true; cellingAll++; } } } } } private void initConnect() { for (int row = 0; row < N; row++) { for (int col = 0; col < M; col++) { union(row, col, row - 1, col); union(row, col, row + 1, col); union(row, col, row, col - 1); union(row, col, row, col + 1); } } } private int find(int row, int col) { int stackSize = 0; int index = row * M + col; while (index != fatherMap[index]) { stack[stackSize++] = index; index = fatherMap[index]; } while (stackSize != 0) { fatherMap[stack[--stackSize]] = index; } return index; } private void union(int r1, int c1, int r2, int c2) { if (valid(r1, c1) && valid(r2, c2)) { int father1 = find(r1, c1); int father2 = find(r2, c2); if (father1 != father2) { int size1 = sizeMap[father1]; int size2 = sizeMap[father2]; boolean status1 = cellingSet[father1]; boolean status2 = cellingSet[father2]; if (size1 <= size2) { fatherMap[father1] = father2; sizeMap[father2] = size1 + size2; if (status1 ^ status2) { cellingSet[father2] = true; cellingAll += status1 ? size2 : size1; } } else { fatherMap[father2] = father1; sizeMap[father1] = size1 + size2; if (status1 ^ status2) { cellingSet[father1] = true; cellingAll += status1 ? size2 : size1; } } } } } private boolean valid(int row, int col) { return row >= 0 && row < N && col >= 0 && col < M && grid[row][col] == 1; } public int cellingNum() { return cellingAll; } public int finger(int row, int col) { grid[row][col] = 1; int cur = row * M + col; if (row == 0) { cellingSet[cur] = true; cellingAll++; } fatherMap[cur] = cur; sizeMap[cur] = 1; int pre = cellingAll; union(row, col, row - 1, col); union(row, col, row + 1, col); union(row, col, row, col - 1); union(row, col, row, col + 1); int now = cellingAll; if (row == 0) { return now - pre; } else { return now == pre ? 0 : now - pre - 1; } } } }