Skip to content

Commit d6f9d93

Browse files
Bricks Falling When Hit
1 parent 23395a1 commit d6f9d93

File tree

2 files changed

+240
-0
lines changed

2 files changed

+240
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ My accepted leetcode solutions to some of the common interview problems.
105105
- [Number of Distinct Islands](problems/src/depth_first_search/NumberOfDistinctIslands.java) (Medium)
106106
- [Number of Distinct Islands II](problems/src/depth_first_search/NumberOfDistinctIslandsII.java) (Hard)
107107
- [Smallest Rectangle Enclosing Black Pixels](problems/src/depth_first_search/SmallestRectangleEnclosingBlackPixels.java) (Hard)
108+
- [Bricks Falling When Hit](problems/src/depth_first_search/BricksFallingWhenHit.java) (Hard)
108109

109110
#### [Design](problems/src/design)
110111

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
package depth_first_search;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* Created by gouthamvidyapradhan on 01/07/2018.
8+
* 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
9+
* directly connected to the top of the grid, or at least one of its (4-way) adjacent bricks will not drop.
10+
11+
We will do some erasures sequentially. Each time we want to do the erasure at the location (i, j), the brick (if it
12+
exists) on that location will disappear, and then some other bricks may drop because of that erasure.
13+
14+
Return an array representing the number of bricks that will drop after each erasure in sequence.
15+
16+
Example 1:
17+
Input:
18+
grid = [[1,0,0,0],[1,1,1,0]]
19+
hits = [[1,0]]
20+
Output: [2]
21+
Explanation:
22+
If we erase the brick at (1, 0), the brick at (1, 1) and (1, 2) will drop. So we should return 2.
23+
Example 2:
24+
Input:
25+
grid = [[1,0,0,0],[1,1,0,0]]
26+
hits = [[1,1],[1,0]]
27+
Output: [0,0]
28+
Explanation:
29+
When we erase the brick at (1, 0), the brick at (1, 1) has already disappeared due to the last move. So each
30+
erasure will cause no bricks dropping. Note that the erased brick (1, 0) will not be counted as a dropped brick.
31+
32+
33+
Note:
34+
35+
The number of rows and columns in the grid will be in the range [1, 200].
36+
The number of erasures will not exceed the area of the grid.
37+
It is guaranteed that each erasure will be different from any other erasure, and located inside the grid.
38+
An erasure may refer to a location with no brick - if it does, no bricks drop.
39+
40+
Solution: O(R x C): Erase all the bricks in the grid and do a union of all the bricks using a union-find disjoint set.
41+
(A modified union-find disjoint set is necessary to keep track of size of the connected component and to check
42+
if its connected to roof or not)
43+
Once you have the different connected components of the grid, solve the problem in the reverse order by
44+
iterating the hits in the reverse order. First set 1 in the grid for each hits and count the connected bricks
45+
in all four directions which are not linked to roof of the grid.
46+
47+
*/
48+
public class BricksFallingWhenHit {
49+
50+
private static final int[] R = {0, 0, 1, -1};
51+
private static final int[] C = {1, -1, 0, 0};
52+
53+
/**
54+
*
55+
* @author gouthamvidyapradhan
56+
* Class to represent UnionFind Disjoint Set
57+
*
58+
*/
59+
private static class UnionFind {
60+
private int[] p;
61+
private int[] rank;
62+
private boolean[] roof;
63+
private int[] size;
64+
65+
UnionFind(int s){
66+
this.p = new int[s];
67+
this.rank = new int[s];
68+
this.size = new int[s];
69+
this.roof = new boolean[s];
70+
init();
71+
}
72+
/**
73+
* Initialize with its same index as its parent
74+
*/
75+
private void init() {
76+
for(int i=0; i<p.length; i++) {
77+
p[i] = i;
78+
size[i] = 1;
79+
}
80+
}
81+
/**
82+
* Find the representative vertex
83+
* @param i
84+
* @return
85+
*/
86+
private int findSet(int i) {
87+
if(p[i] != i){
88+
p[i] = findSet(p[i]);
89+
}
90+
return p[i];
91+
}
92+
93+
/**
94+
* Set as roof
95+
* @param i
96+
*/
97+
public void setAsRoof(int i){
98+
roof[i] = true;
99+
}
100+
/**
101+
* Perform union of two vertex
102+
* @param i
103+
* @param j
104+
* @return true if union is performed successfully, false otherwise
105+
*/
106+
public boolean union(int i, int j) {
107+
int x = findSet(i);
108+
int y = findSet(j);
109+
if(x != y) {
110+
if(rank[x] > rank[y]){
111+
p[y] = p[x];
112+
roof[x] = (roof[x] || roof[y]);
113+
size[x] = size[x] + size[y];
114+
}
115+
else {
116+
p[x] = p[y];
117+
roof[y] = (roof[x] || roof[y]);
118+
size[y] = size[x] + size[y];
119+
if(rank[x] == rank[y]){
120+
rank[y]++; //increment the rank
121+
}
122+
}
123+
return true;
124+
}
125+
return false;
126+
}
127+
128+
/**
129+
* is attached to roof
130+
* @param i
131+
* @return
132+
*/
133+
public boolean isRoof(int i){
134+
return roof[findSet(i)];
135+
}
136+
137+
/**
138+
* is attached to roof
139+
* @param i
140+
* @return
141+
*/
142+
public int size(int i){
143+
return size[findSet(i)];
144+
}
145+
}
146+
147+
/**
148+
*
149+
* @param args
150+
* @throws Exception
151+
*/
152+
public static void main(String[] args) throws Exception{
153+
int[][] grid = {{1,1,1,1,1}, {0, 0, 1, 0, 1}, {1, 0, 1, 0, 1}, {1, 1, 1, 0, 1}};
154+
int[][] hits = {{1,2}, {2,2}, {2, 4}, {0, 4}, {0, 0}};
155+
int[] r = new BricksFallingWhenHit().hitBricks(grid, hits);
156+
for(int i = 0; i < r.length; i ++){
157+
System.out.print(r[i] + " ");
158+
}
159+
}
160+
161+
public int[] hitBricks(int[][] grid, int[][] hits) {
162+
int nR = grid.length;
163+
int nC = grid[0].length;
164+
UnionFind unionFind = new UnionFind((nR * nC) + 1);
165+
for(int i = 0; i < nC; i ++){
166+
if(grid[0][i] == 1){
167+
unionFind.setAsRoof(i + 1);
168+
}
169+
}
170+
for(int k = 0; k < hits.length; k++){
171+
int[] h = hits[k];
172+
if(grid[h[0]][h[1]] == 0){
173+
h[0] = -1;
174+
h[1] = -1;
175+
}else{
176+
grid[h[0]][h[1]] = 0;
177+
}
178+
}
179+
boolean[][] done = new boolean[grid.length][grid[0].length];
180+
for(int i = 0; i < grid.length; i ++){
181+
for(int j = 0; j < grid[0].length; j ++){
182+
if(grid[i][j] == 1 && !done[i][j]){
183+
dfs(i, j, grid, done, unionFind);
184+
}
185+
}
186+
}
187+
int[] result = new int[hits.length];
188+
for(int i = hits.length - 1; i >= 0; i --){
189+
int[] h = hits[i];
190+
int r = h[0];
191+
int c = h[1];
192+
if(r == -1) continue;
193+
grid[r][c] = 1;
194+
int cell = (r * nC) + c + 1;
195+
int sum = 0;
196+
List<Integer> notLinkedToRoof = new ArrayList<>();
197+
List<Integer> linkedToRoof = new ArrayList<>();
198+
for(int k = 0; k < 4; k ++){
199+
int newR = r + R[k];
200+
int newC = c + C[k];
201+
if(newR >=0 && newR < nR && newC >= 0 && newC < nC && grid[newR][newC] == 1){
202+
int newCell = (newR * nC) + newC + 1;
203+
if(unionFind.isRoof(newCell)){
204+
linkedToRoof.add(newCell);
205+
} else{
206+
notLinkedToRoof.add(newCell);
207+
}
208+
}
209+
}
210+
for(int nr : notLinkedToRoof){
211+
unionFind.union(cell, nr);
212+
}
213+
if(!linkedToRoof.isEmpty() || unionFind.isRoof(cell)){
214+
sum += (unionFind.size(cell) - 1);
215+
}
216+
for(int rr : linkedToRoof){
217+
unionFind.union(cell, rr);
218+
}
219+
result[i] = sum;
220+
}
221+
return result;
222+
}
223+
224+
private void dfs(int r, int c, int[][] grid, boolean[][] done, UnionFind unionFind){
225+
done[r][c] = true;
226+
int cell = (r * grid[0].length) + c + 1;
227+
for(int i = 0; i < 4; i ++){
228+
int newR = r + R[i];
229+
int newC = c + C[i];
230+
if(newR >= 0 && newR < grid.length && newC >= 0 && newC < grid[0].length){
231+
if(grid[newR][newC] == 1 && !done[newR][newC]){
232+
int newCell = (newR * grid[0].length) + newC + 1;
233+
unionFind.union(cell, newCell);
234+
dfs(newR, newC,grid, done, unionFind);
235+
}
236+
}
237+
}
238+
}
239+
}

0 commit comments

Comments
 (0)