-
Notifications
You must be signed in to change notification settings - Fork 23
/
200. Number of Islands.java
executable file
·323 lines (282 loc) · 9.9 KB
/
200. Number of Islands.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
M
tags: DFS, BFS, Union Find, Matrix DFS
time: O(n)
space: O(n)
给一个2Dmatrix, 里面是1和0, 找#of island.
#### Method1, DFS
- visit all nodes connected with the starting node
- double for loop, test all starting nodes
- val == 1: 1) count++; 2)DFS from this (i,j);
- Mark visited (x,y) = '0'
- time: O(n), visit all nodes
- space: O(n), stack
#### Method2, Union Find
- 可以用union-find, 就像Number of island II 一样.
- 只不过这个不Return list, 而只是# of islands
- Union Find is independent from the problem: it models the union status of integers.
- Return the total # of unions (which is # of islands)
- in reality: it is a bit slow.
- time: visit all nodes just once, O(n). Union Find will visit all nodes once and union them
- space: O(n), union find takes O(n) space
- 记住UnionFind的模板和几个变化(Connecting Graph I, II, III), 最后归总的代码写起来就比较简单.
#### Method3: BFS
- use queue to hold 1 island, keep adding 4-direction islands; mark visited with '0'
- check entire board for any remaining one.
```
/*
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands.
An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically.
You may assume all four edges of the grid are all surrounded by water.
Example 1:
Input:
11110
11010
11000
00000
Output: 1
Example 2:
Input:
11000
11000
00100
00011
Output: 3
*/
/*
Method1: DFS
- DFS and flip the bit-1 on the grid to 0 as we go: to 4 different directions
- Loop through all positions
- Visited spots won't be visited again because they are updated to '0'
*/
class Solution {
private int[] dx = {1, -1, 0, 0};
private int[] dy = {0, 0, 1, -1};
public int numIslands(char[][] grid) {
if (grid == null) return 0;
int count = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == '1') {
count++;
dfs(grid, i, j);
}
}
}
return count;
}
private void dfs(char[][] grid, int x, int y) {
if (validateInput(grid, x, y)) return;
grid[x][y] = '0';
for (int i = 0; i < dx.length; i++) {
dfs(grid, x + dx[i], y + dy[i]);
}
}
private boolean validateInput(char[][] grid, int x, int y) {
return x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || grid[x][y] == '0';
}
}
/*
Method2: Union Find
Similart to ConnectingGraph, and we count # of unions left.
Build UnionFind and let query return # of unions left (isolated island in this problem).
Need to know which island to connect/union, need to go 4 directions.
Convert 2D matrix to 1D index = rowNum * numOfColumn + colNum
*/
class Solution {
int[] dx = {1, -1, 0, 0};
int[] dy = {0, 0, 1, -1};
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null) return 0;
int m = grid.length, n = grid[0].length;
// init with # of island blocks, goal is to connect them all.
UnionFind uf = new UnionFind(m * n);
uf.setCount(countIsland(grid));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == '1') {
for (int k = 0; k < dx.length; k++) { // 4 directions
int x = i + dx[k], y = j + dy[k];
if (!validate(grid, x, y)) { // Attemp to union all of the 4 directions
uf.union(convertToIndex(i, j, n), convertToIndex(x, y, n));
}
}
}
}
}
// output the united total # of islands
return uf.query();
}
private int countIsland(char[][] grid) {
int m = grid.length, n = grid[0].length;
int count = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
count += grid[i][j] == '1' ? 1 : 0;
}
}
return count;
}
// 1D index = rowNum * numOfColumn + colNum
private int convertToIndex(int x, int y, int rowLength) {
return x * rowLength + y;
}
private boolean validate(char[][] grid, int x, int y) {
return x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || grid[x][y] == '0';
}
}
// Union Find definition
class UnionFind {
int father[] = null;
int count;
public UnionFind(int n) {
father = new int[n];
for (int i = 0; i < n; i++) {
father[i] = i;
}
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
father[rootX] = rootY;
count--;
}
}
public int query() {
return count;
}
public void setCount(int value) {
count = value;
}
private int find(int x) {
if (father[x] == x) return x;
return father[x] = find(father[x]);
}
}
// Method3: BFS
class Solution {
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) return 0;
int count = 0;
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == '1') {
count++;
grid[i][j] = '0';
queue.offer(i * grid[0].length + j);
processQueue(queue, grid);
}
}
}
return count;
}
int[] dx = {0, 0, 1, -1};
int[] dy = {1, -1, 0, 0};
public void processQueue(Queue<Integer> queue, char[][] grid) {
int m = grid.length, n = grid[0].length;
while(!queue.isEmpty()) {
int key = queue.poll();
int x = key / n, y = key % n;
for (int i = 0; i < 4; i++) {
int nx = x + dx[i], ny = y + dy[i];
if (validate(grid, nx, ny)) {
grid[nx][ny] = '0';
queue.offer(nx * n + ny);
}
}
}
}
private boolean validate(char[][] grid, int x, int y) {
return x >= 0 && x < grid.length && y >= 0 && y < grid[0].length && grid[x][y] == '1';
}
}
/*
Thoughts:
UnionFind with map rather than array
Traverse all points of grid and count the total number of island. See Number of Islands II for details.
Note: need to initialize the 1D array first with all 1's.
Therefore, when we start perform union-find, we already have knowledge of entire island status.
However, it's not as straight-forward as DFS though.
*/
class Solution {
class UnionFind {
private HashMap<Integer, Integer> map = new HashMap<>();
/*
Model the disjoint set with 1D array
During initialization, assume each spot has itself as the parent
*/
public UnionFind(int size) {
for (int i = 0; i < size; i++) {
map.put(i, i);
}
}
/*
Use one key and find out the root parent of this set where they key belongs to.
*/
public int findRootParent(int item) {
int parent = map.get(item);
while (parent != map.get(parent)) {
parent = map.get(parent);
}
return parent;
}
/*
Find the root parent of each item. If the root parent is different,
join them together by adding them into the map as <key, value> pair.
*/
public void union(int itemX, int itemY) {
int parentX = findRootParent(itemX);
int parentY = findRootParent(itemY);
if (parentX != parentY) {
map.put(parentX, parentY);
}
}
}
private int[] dx = {1, -1, 0, 0};
private int[] dy = {0, 0, 1, -1};
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return 0;
}
int count = 0;
int m = grid.length;
int n = grid[0].length;
final int[] islands = new int[m * n];
final UnionFind unionFind = new UnionFind(m * n);
// Initialize island
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == '1') {
int pos = i * n + j;
islands[pos] = 1;
count++;
}
}
}
// Merge island and decrease count if on merged island
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int pos = i * n + j;
if (islands[pos] != 1) {
continue;
}
for (int k = 0; k < dx.length; k++) {
int adjX = i + dx[k];
int adjY = j + dy[k];
int adjPos = adjX * n + adjY;
if (adjX >= 0 && adjX < m && adjY >= 0 && adjY < n && islands[adjPos] == 1) {
int currSpotRoot = unionFind.findRootParent(pos);
int adjSpotRoot = unionFind.findRootParent(adjPos);
if (currSpotRoot != adjSpotRoot) {
count--;
unionFind.union(currSpotRoot, adjSpotRoot);
}
}
}
}
}
return count;
}
}
```