# [leetcode/lintcode 题解] 谷歌面试题：打砖块

1. 网格的行列数在 [1, 200] 的范围内.
2. 每次消除的位置不重复, 并且一定在网格范围内.
3. 如果要消除的位置没有砖块, 那么什么都不会发生.
4. 行下标越小则越低, 也就是说, 行下标为 0 的位置连接着网格底部.

### 样例

输入: grid = [[1,0,0,0],[1,1,1,0]], hits = [[1,0]]

输入: grid = [[1,0,0,0],[1,1,0,0]], hits = [[1,1],[1,0]]

输入: grid = [[1],[1],[1]], hits = [[0,0],[0,0]]

【题解】

public class Solution {
/**
* @param grid: a grid
* @param hits: some erasures order
* @return: an array representing the number of bricks that will drop after each erasure in sequence
*/
class UnionFind{
int[] father;
int[] count;
UnionFind(int len) {
father = new int[len];
count = new int[len];
for (int i = 0; i < len ; i++) {
father[i] = i;
count[i] = 1;
}
}

int find(int toFind) {
while(father[toFind] != toFind) {
father[toFind] = father[father[toFind]];
toFind = father[toFind];
}
}

void union(int a, int b) {
int fatherA = find(a);
int fatherB = find(b);
if (fatherA != fatherB) {
father[fatherA] = fatherB;
count[fatherB] += count[fatherA];
}
}
}

public int[] hitBricks(int[][] grid, int[][] hits) {
int m = grid.length;
int n = grid[0].length;
UnionFind uf = new UnionFind(m * n + 1);
for (int[] hit : hits) {
if (grid[hit[0]][hit[1]] == 1) {
grid[hit[0]][hit[1]] = 2;
}
}

for (int i = 0 ; i < m; i++)  {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1) {
unionAround(i, j, grid, uf);
}
}
}

int count = uf.count[uf.find(0)];
int[] res = new int[hits.length];

for (int i = hits.length -1; i >= 0; i--) {
int[] hit = hits[i];
if (grid[hit[0]][hit[1]] == 2) {
unionAround(hit[0], hit[1], grid, uf);
grid[hit[0]][hit[1]] = 1;
}
int newCount = uf.count[uf.find(0)];
res[i] = (newCount - count > 0) ? newCount - count - 1 : 0;
count = newCount;
}
return res;
}

private void unionAround(int x, int y, int[][] grid, UnionFind uf) {
int m = grid.length;
int n = grid[0].length;
int[] dx = new int[] {-1, 1, 0, 0};
int[] dy = new int[] {0, 0, -1, 1};
for (int i = 0; i < 4; i++) {
int nextX = x + dx[i];
int nextY = y + dy[i];
if (nextX < 0 || nextX >= m || nextY < 0 || nextY >= n) continue;
if (grid[nextX][nextY] == 1) {
uf.union(x * n + y + 1, nextX * n + nextY + 1);
}
}
if (x == 0) {
uf.union(x * n + y + 1, 0);
}
}
}

08-05 44

08-04 108

07-30 241

07-29 239

07-24 427

07-21 784

07-20 389

07-17 732

07-16 1215

07-03 1240

#### 阿里P8加面Coding，刷题爱好者的春天来了？

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