标签:
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. Example: Given m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]]. Initially, the 2d grid grid is filled with water. (Assume 0 represents water and 1 represents land). 0 0 0 0 0 0 0 0 0 Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land. 1 0 0 0 0 0 Number of islands = 1 0 0 0 Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land. 1 1 0 0 0 0 Number of islands = 1 0 0 0 Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land. 1 1 0 0 0 1 Number of islands = 2 0 0 0 Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land. 1 1 0 0 0 1 Number of islands = 3 0 1 0 We return the result as an array: [1, 1, 2, 3] Challenge: Can you do it in time complexity O(k log mn), where k is the length of the positions?
Union Find
参考:https://leetcode.com/discuss/69572/easiest-java-solution-with-explanations
第三行代码非常漂亮,把4个方向定义出来
1 public class Solution { 2 public List<Integer> numIslands2(int m, int n, int[][] positions) { 3 int[][] dirs = new int[][]{{-1,0},{1,0},{0,1},{0,-1}}; 4 unionFind uf = new unionFind(m*n); 5 List<Integer> res = new ArrayList<Integer>(); 6 for (int[] pos : positions) { 7 int cur = pos[0]*n + pos[1]; 8 uf.ids[cur] = cur; 9 uf.count++; 10 for (int[] dir : dirs) { 11 int x = dir[0] + pos[0]; 12 int y = dir[1] + pos[1]; 13 int nb = x*n+y; 14 if (x<0 || x>=m || y<0 || y>=n || uf.ids[nb]==-1) continue; 15 if (uf.find(nb) != uf.find(cur)) { 16 uf.union(nb, cur); 17 } 18 } 19 res.add(uf.count); 20 } 21 return res; 22 } 23 24 public class unionFind { 25 int[] ids; 26 int count; 27 public unionFind(int num) { 28 this.ids = new int[num]; 29 Arrays.fill(ids, -1); 30 this.count = 0; 31 } 32 public int find(int num) { 33 return ids[num]; 34 } 35 public boolean union(int n1, int n2) { 36 int id1=ids[n1], id2=ids[n2]; 37 if (id1 != id2) { 38 for (int i=0; i<ids.length; i++) { 39 if (ids[i] == id2) { 40 ids[i] = id1; 41 } 42 } 43 count--; 44 return true; 45 } 46 return false; 47 } 48 } 49 }
Union Find方法2:
This is a basic union-find
problem. Given a graph with points being added, we can at least solve:
The idea is simple. To represent a list of islands, we use trees. i.e., a list of roots. This helps us find the identifier of an island faster. If roots[c] = p
means the parent of node c is p, we can climb up the parent chain to find out the identifier of an island, i.e., which island this point belongs to:
Do root[root[roots[c]]]... until root[c] == c;
To transform the two dimension problem into the classic UF, perform a linear mapping:
int id = n * x + y;
Initially assume every cell are in non-island set {-1}
. When point A is added, we create a new root, i.e., a new island. Then, check if any of its 4 neighbors belong to the same island. If not,union
the neighbor by setting the root to be the same. Remember to skip non-island cells.
UNION operation is only changing the root parent so the running time is O(1)
.
FIND operation is proportional to the depth of the tree. If N is the number of points added, the average running time is O(logN)
, and a sequence of 4N
operations take O(NlogN)
. If there is no balancing, the worse case could be O(N^2)
.
Remember that one island could have different roots[node]
value for each node. Becauseroots[node]
is the parent of the node, not the highest root of the island. To find the actually root, we have to climb up the tree by calling findIsland function.
Here I‘ve attached my solution. There can be at least two improvements: union by rank
& pass compression
. However I suggest first finish the basis, then discuss the improvements.
Cheers!
1 int[][] dirs = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; 2 3 public List<Integer> numIslands2(int m, int n, int[][] positions) { 4 List<Integer> result = new ArrayList<>(); 5 if(m <= 0 || n <= 0) return result; 6 7 int count = 0; // number of islands 8 int[] roots = new int[m * n]; // one island = one tree 9 Arrays.fill(roots, -1); 10 11 for(int[] p : positions) { 12 int root = n * p[0] + p[1]; // assume new point is isolated island 13 roots[root] = root; // add new island 14 count++; 15 16 for(int[] dir : dirs) { 17 int x = p[0] + dir[0]; 18 int y = p[1] + dir[1]; 19 int nb = n * x + y; 20 if(x < 0 || x >= m || y < 0 || y >= n || roots[nb] == -1) continue; 21 22 int rootNb = findIsland(roots, nb); 23 if(roots[root] != rootNb) { // if neighbor is in another island 24 roots[root] = rootNb; // union two islands 25 root = rootNb; // current tree root = joined tree root 26 count--; 27 } 28 } 29 30 result.add(count); 31 } 32 return result; 33 } 34 35 public int findIsland(int[] roots, int id) { 36 while(id != roots[id]) id = roots[id]; 37 return id; 38 }
Leetcode: Number of Islands II
标签:
原文地址:http://www.cnblogs.com/EdwardLiu/p/5087633.html