1. 程式人生 > >803. Bricks Falling When Hit

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 版權宣告:本文為博主原創文章,轉載請附上博文連結