1. 程式人生 > >Leetcode 305. Number of Islands II

Leetcode 305. Number of Islands II

Problem:

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:

Input: m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]]
Output: [1,1,2,3]

Explanation:

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

Follow up:

Can you do it in time complexity O(k log mn), where k is the length of the positions?

 

Note:

  1. You may assume all letters are in lowercase.
  2. You may assume that if a is a prefix of b, then a must appear before b in the given dictionary.
  3. If the order is invalid, return an empty string.
  4. There may be multiple valid order of letters, return any one of them is fine.

Solution:

  經典的Union Find問題,對於Union和Find函式,我在Union Find演算法總結裡已經講述了基本原理,在此不加贅述。這道題的難點在於當加入一個1之後,它可能將其上下左右四個方向的塊連成一個整體,比如

    0 1 0    0 1 0

    1 0 1     ->   1 1 1

    0 1 0    0 1 0

  這種情況下塊的數量由4變為1。我們發現,若中心位置的上下左右都為0,則塊的數量加1,而當中心位置依次與上下左右四個塊做四次Union操作,而每一次Union操作都會將塊的數量減少1。因此1 = (4+1)-1-1-1-1得到Union後的塊數。這裡要注意一種特殊情況:

    1 1 0    0 1 0

    1 0 1     ->   1 1 1

    0 1 0    0 1 0

  即中心位置上面的1和左面的1其實屬於同一個塊,所以當中心的1和左側的1進行Union操作之後,左側的1和中心的1以及上面的1有著相同的根節點,因此在中心的1和上面的1進行Union操作時不需要將塊的數量減1。在這部分程式碼中,我將Union函式設定了一個返回值,用於判斷兩個塊是否有共同的根節點(不設返回值其實也可以,我認為這樣寫程式碼更優雅)。

Code:

 

 1 class Solution {
 2 public:
 3     int Find(vector<int> &parent,int target){
 4         if(parent[target] == target)
 5             return target;
 6         return Find(parent,parent[target]);
 7     }
 8     bool Union(vector<int> &parent,vector<int> &rank,int first,int second){
 9         int px = Find(parent,first);
10         int py = Find(parent,second);
11         if(px == py) return false;
12         if(rank[px] > rank[py]) parent[py] = px;
13         else if(rank[py] > rank[px]) parent[px] = py;
14         else{
15             parent[py] = px;
16             rank[px]++;
17         }
18         return true;
19     }
20     vector<int> numIslands2(int m, int n, vector<pair<int, int>>& positions) {
21         vector<int> result;
22         vector<int> parent(m*n,0);
23         vector<int> rank(m*n,0);
24         vector<bool> visited(m*n,false);
25         int count = 0;
26         for(int i = 0;i != m;++i){
27             for(int j = 0;j != n;++j){
28                 parent[i*n+j] = i*n+j;
29             }
30         }
31         for(int i = 0;i != positions.size();++i){
32             int x = positions[i].first;
33             int y = positions[i].second;
34             int index = x*n+y;
35             visited[index] = true;
36             count++;
37             if(x-1 >= 0 && visited[index-n] && Union(parent,rank,index,index-n))
38                 count--;
39             if(x+1 < m && visited[index+n] && Union(parent,rank,index,index+n)) 
40                 count--;
41             if(y-1 >= 0 && visited[index-1] && Union(parent,rank,index,index-1)) 
42                 count--;
43             if(y+1 < n && visited[index+1] && Union(parent,rank,index,index+1)) 
44                 count--;
45             result.push_back(count);
46         }
47         return result;
48     }
49 };