803. Bricks Falling When Hit

看不懂 union find 的代码
https://leetcode.com/problems/bricks-falling-when-hit/discuss/141229/JAVA-Simple-DFS-16ms-reversely-add-bricks-back


Very clever idea using -1 to stop visiting the points already erased, 2 to stop visiting points still connected. So we just need to count how many 1s can still be reached from the current point!






// bfs . 
Memory Limit Exceeded


class Solution {
    private static final int[][] dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
    public int[] hitBricks(int[][] matrix, int[][] hits) {
        int n = hits.length;
        int[] res = new int[n];
        remove(matrix, hits);
        
        for(int i = n - 1; i >= 0; i--){
            int numOnesBefore = oneConnectedTop(matrix);
            addBack(matrix, hits[i]);
            int numOnesAfter = oneConnectedTop(matrix);
            res[i] = numOnesAfter - numOnesBefore;
        }
        return res;
    }
    
    private void remove(int[][] matrix, int[][] hits){
        for(int[] hit : hits){
            int x = hit[0];
            int y = hit[1];
            if(matrix[x][y] == 1) matrix[x][y] = 0;
        } 
    }
    
    private int oneConnectedTop(int[][] matrix){
        boolean[][] visited = new boolean[matrix.length][matrix[0].length];
        int count = 0;
        // do a bfs from all the top rows that are 1s 
        Queue<int[]> queue = new LinkedList<>();
        for(int i = 0; i < matrix[0].length; i++){
            if(matrix[0][i] == 1) queue.offer(new int[]{0, i});
        }
        while(!queue.isEmpty()){
            int[] cur = queue.poll();
            count++;
            for(int[] dir : dirs){
                int x = cur[0] + dir[0];
                int y = cur[1] + dir[1];
                // check boundary 
                if(x < 0 || y < 0 || x >= matrix.length || y >= matrix[0].length || matrix[x][y] == 0 || visited[x][y]) continue;
                // else , its not visited and it's 1 
                queue.offer(new int[]{x, y});
            }
        }
        return count; 
    }
    
    private void addBack(int[][] matrix, int[] hit){
        int x = hit[0];
        int y = hit[1];
        if(matrix[x][y] == 0) matrix[x][y] = 1;
    }
}





















https://www.youtube.com/watch?v=UrMZrAyyliw

https://blog.csdn.net/brazy/article/details/79678332


https://leetcode.com/problems/bricks-falling-when-hit/solution/



We have a grid of 1s and 0s; the 1s in a cell represent bricks.  A brick will not drop if and only if it is directly connected to the top of the grid, or at least one of its (4-way) adjacent bricks will not drop.
We will do some erasures sequentially. Each time we want to do the erasure at the location (i, j), the brick (if it exists) on that location will disappear, and then some other bricks may drop because of that erasure.
Return an array representing the number of bricks that will drop after each erasure in sequence.
Example 1:
Input: 
grid = [[1,0,0,0],[1,1,1,0]]
hits = [[1,0]]
Output: [2]
Explanation: 
If we erase the brick at (1, 0), the brick at (1, 1) and (1, 2) will drop. So we should return 2.
Example 2:
Input: 
grid = [[1,0,0,0],[1,1,0,0]]
hits = [[1,1],[1,0]]
Output: [0,0]
Explanation: 
When we erase the brick at (1, 0), the brick at (1, 1) has already disappeared due to the last move. So each erasure will cause no bricks dropping.  Note that the erased brick (1, 0) will not be counted as a dropped brick.






So for the first example, (1,1) and (1,2) get knocked out because there is no longer a brick connecting them to the top:
1 0 0 0 . . . . . . . . . . . . . . 1 0 0 0 . . . . . . . . . . . . . . . . . . . . . . . . . . 1 0 0 0
1 1 1 0 . . . erase (1, 0). . 0 1 1 0 . . . (1,1) and (1,2) then drop . . . 0 0 0 0 . . . leaving you with the answer of 2 bricks being dropped as a result of the erasure.
.
As for the second example, that should be invalid input as there is nothing connecting the second row to the top to begin with. Unless you meant the description's example of [[1, 0, 0, 0], [1, 1, 0, 0]] which is:
1 0 0 0 . . . . . . . . . . . . . . . 1 0 0 0
1 1 0 0 . . .erase (1, 1) . . . 1 0 0 0 . . . and the other bricks are still connected to the top, resulting in 0 bricks dropped after the erasure.
.
For a more complex example:
1 0 0 0 0 . . . . . . . . . . . . . . . . . . . . . . 1 0 0 0 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 0 0 0 0
1 0 0 1 1 . . . . . . . . . . . . . . . . . . . . . .  1 0 0 1 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   1 0 0 0 0
1 1 1 1 0 . . . . . . . . . . . . . . . . . . . . . .   1 1 0 1 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  1 1 0 0 0
1 0 1 0 0 . . erasing (2, 2) gives . . . . 1 0 1 0 0 . . . which drops the stranded 4 bricks . . 1 0 0 0 0



First, remove all the points(bricks ) we are asked to break , say the points are (1, 0), (2, 2) 
after removed (1, 0) and (2, 2) from the graph. 

We add the points back to the graph in reverse order, we add (2, 2) back to the graph first, before we add the point back , we check the size of the connected components that is connected to the roof, say the size is 3, 
After we add the point (2, 2) back to the graph, we check the size of he connected components that is connected to the roof, say it’s 6, then the size difference is the number of bricks dropped if we remove(2, 2) in the original problem setting. 

So now we know the size of the connected components that is connected to the roof, which is 6, after the point (2 , 2) is added back , 

Now we need to take care of the point (1, 0), after we add (1, 0) back to the graph,  we check the size of the connected components that is connected to the roof, let’s say it’s 8, then the size difference is 2, which is the number of dropping bricks 







.
At least that it how I understood this problem in order to solve it.

EDIT: Sorry for the formatting of my grid depictions, I was unaware that this site hated whitespace

Solution 1 : regular  dfs/ bfs 


Solution 2 : reverse union find  or reverse dfs 

Reverse dfs 
https://leetcode.com/problems/bricks-falling-when-hit/discuss/141229/JAVA-Simple-DFS-16ms-reversely-add-bricks-back

The idea is simple.

1. Remove all bricks in hits. If the cell is originly 1, we set it to -1 so that we can add the brick back;
2. DFS from the first row (roof), set all cells of bricks to 2 so that we know these cells have been visited.
3. Iterate from the last hit to the first one, i.e., put the erasured bricks back. For every step:
3.1 if the cell is 0, continue;
3.2 else the cell is -1. Check if the cell is attathed to the roof (or any cell with value 2)
If no, continue;
Else, reuse the dfs function to count all the connected bricks (cells with value 1). These are bricks that fell down when we erase the hit! Remember to minus 1, which is the brick we erased.





Reverse union find : 

好的,现在来看一个O(N*N)的做法,就是使用并查集,不过要把这道题和并查集联系起来的确是有难度的,不容易想到,来看一下思路:首先得逆向思维,先把要移除的方块都在矩阵中移除,然后从后往前一块一块的方块往原矩阵中加,看能连通起多少块不能包含第一行方块的连通块的个数,这就是这次移除造成的自动掉落的方块数。那具体该如何实现呢?把所有要移除的方块从矩阵中移除后,首先把矩阵中剩下的方块中直接相邻的方块连接在一起,相当于在这两个节点之间加一条边(图的思维),处理的同时要注意记录每一个连通块已有的节点的个数,同时还要记录这个连通块是否包含第一行,然后就是从最后一次移除往前算,设要移除的方块为A,判断和A是否有直接相邻的方块B,如果这两块方块不属于同一个连通块,并且B所属连通块不包含第一行,那就记录这个连通块的个数,因为这个连通块通过添加A可能就包含第一行了,这也就是移除时会自动掉落的连通块,同时也把这两个节点之间连接一条边,同时更新记录,最后说记录的会自动掉落的连通块个数不一定就是结果,还要判断A所属连通块是不是包含第一行,如果不包含,那就是说明A是在之前就已经掉落的,那此次移除的结果就是0,最后再把原图中连通块A添上,然后处理下一个,OK,这道题这样就可以顺利解决了。
--------------------- 
作者:Receiling 
来源:CSDN 
原文:https://blog.csdn.net/brazy/article/details/79678332 
版权声明:本文为博主原创文章,转载请附上博文链接

猜你喜欢

转载自www.cnblogs.com/tobeabetterpig/p/9930169.html