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 };

 

posted on 2018-12-27 05:38  周浩炜  阅读(145)  评论(0编辑  收藏  举报

导航