Number of Island II
Question
A 2d grid map of m rows and n columns is initially filled with water. We may perform an addLand operation which turns the water at position (row, col) into a land. Given a list of positions to operate, count the number of islands after each addLand operation. 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.
Solution
這題是 Number of Island 的 follow-up,基本上這種給圖找連結的題目,都可以用 Union-Find 來實現。在 Number of Island 那題,用 DFS 是一個非常直觀的算法。但在這題,帶進 UF 的方法會比較好做。需要注意的地方:
- linear mapping:n * X + Y (這個套用在所有 2d 轉 1d 的情況)
- 在同個 island 裡會有不同的 roots[node],因為 roots[node] 只記錄當前這個 node 的 parent。為了找到最終的 parent,要特別寫一個 findIsIand 來實現
int[][] dirs = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
public List<Integer> numIslands2(int m, int n, int[][] positions) {
List<Integer> result = new ArrayList<>();
if(m <= 0 || n <= 0) return result;
int count = 0; // number of islands
int[] roots = new int[m * n]; // one island = one tree
Arrays.fill(roots, -1);
for(int[] p : positions) {
int root = n * p[0] + p[1]; // assume new point is isolated island
roots[root] = root; // add new island
count++;
for(int[] dir : dirs) {
int x = p[0] + dir[0];
int y = p[1] + dir[1];
int nb = n * x + y;
if(x < 0 || x >= m || y < 0 || y >= n || roots[nb] == -1) continue;
int rootNb = findIsland(roots, nb);
if(root != rootNb) { // if neighbor is in another island
roots[root] = rootNb; // union two islands
root = rootNb; // current tree root = joined tree root
count--;
}
}
result.add(count);
}
return result;
}
public int findIsland(int[] roots, int id) {
while(id != roots[id]) id = roots[id];
return id;
}
Bonus
Path Compression 只要在 findIsland 裡面加入這行就可以把樹高度壓縮,讓程式效率更好
roots[id] = roots[roots[id]];