803. 打砖块

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

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

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

注意,消除可能指向是没有砖块的空白位置,如果发生这种情况,则没有砖块掉落。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/bricks-falling-when-hit
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {

    private int[][] directions = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};

    public int[] hitBricks(int[][] grid, int[][] hits) {
        for (int[] hit : hits) {
            if (grid[hit[0]][hit[1]] == 1) {
                grid[hit[0]][hit[1]] = 2;
            }
        }
        UnionSet unionSet = new UnionSet(grid);
        for (int i = 0; i < grid.length; ++i) {
            for (int j = 0; j < grid[0].length; ++j) {
                if (grid[i][j] == 1) {
                    for (int k = 0; k < directions.length; ++k) {
                        int x = i + directions[k][0];
                        int y = j + directions[k][1];
                        if (x >= 0 && x < grid.length && y >= 0 && y < grid[0].length && grid[x][y] == 1) {
                            unionSet.merge(new int[]{x, y}, new int[]{i, j});
                        }
                    }
                }
            }
        }
        int[] ans = new int[hits.length];
        int total = unionSet.getTotal();
        for (int i = hits.length - 1; i >= 0; --i) {
            if (grid[hits[i][0]][hits[i][1]] == 2) {
                unionSet.set(hits[i]);
                for (int k = 0; k < directions.length; ++k) {
                    int x = hits[i][0] + directions[k][0];
                    int y = hits[i][1] + directions[k][1];
                    if (x >= 0 && x < grid.length && y >= 0 && y < grid[0].length && grid[x][y] == 1) {
                        unionSet.merge(new int[]{x, y}, hits[i]);
                    }
                }
                int newTotal = unionSet.getTotal();
                if (newTotal != total) {
                    ans[i] = newTotal - total - 1;
                }
                total = newTotal;
            }
        }
        return ans;
    }
}

class UnionSet {

    /**
     * 图
     */
    private int[][] grid;

    /**
     * 连通块父节点
     */
    private int[] parent;

    /**
     * 连通块内1的个数
     */
    private int[] size;

    /**
     * 连通块是否在墙上
     */
    private boolean[] onWalls;

    /**
     * 在墙上的总数
     */
    private int total;

    public int[] convertIntToCoordinate(int x) {
        return new int[]{x / grid[0].length, x % grid[0].length};
    }

    public int convertCoordinateToInt(int[] coordinate) {
        return coordinate[0] * grid[0].length + coordinate[1];
    }

    public void set(int[] coordinate) {
        size[convertCoordinateToInt(coordinate)] = 1;
        grid[coordinate[0]][coordinate[1]] = 1;
        if (coordinate[0] == 0) {
            onWalls[convertCoordinateToInt(coordinate)] = true;
            total++;
        }
    }

    public int getTotal() {
        return total;
    }

    public UnionSet(int[][] grid) {
        int n = grid.length * grid[0].length;
        this.grid = grid;
        this.parent = new int[n];
        this.onWalls = new boolean[n];
        for (int i = 0; i < n; ++i) {
            parent[i] = i;
        }
        this.size = new int[n];
        this.total = 0;
        for (int i = 0; i < grid.length; ++i) {
            for (int j = 0; j < grid[0].length; ++j) {
                if (grid[i][j] == 1) {
                    int x = convertCoordinateToInt(new int[]{i, j});
                    size[x] = 1;
                    if (i == 0) {
                        onWalls[x] = true;
                        total++;
                    }
                }
            }
        }
    }

    private int find(int x) {
        int f = parent[x];
        if (x == f) {
            return f;
        }
        f = find(f);
        parent[x] = f;
        return f;
    }

    public void merge(int[] c1, int[] c2) {
        int a = convertCoordinateToInt(c1);
        int b = convertCoordinateToInt(c2);
        int f1 = find(a);
        int f2 = find(b);
        if (f1 != f2) {
            int s1 = size[f1];
            int s2 = size[f2];
            boolean onWall = onWalls[f1] | onWalls[f2];
            if (s1 < s2) {
                parent[f1] = f2;
                if (onWall) {
                    if (!onWalls[f1]) {
                        total += size[f1];
                    } else if (!onWalls[f2]) {
                        total += size[f2];
                    }
                }
                size[f2] += size[f1];
                onWalls[f2] = onWall;
                size[f1] = 0;
            } else {
                parent[f2] = f1;
                if (onWall) {
                    if (!onWalls[f1]) {
                        total += size[f1];
                    } else if (!onWalls[f2]) {
                        total += size[f2];
                    }
                }
                size[f1] += size[f2];
                onWalls[f1] = onWall;
                size[f2] = 0;
            }
        }
    }
}
posted @ 2022-02-10 11:40  Tianyiya  阅读(51)  评论(0)    收藏  举报