【LeetCode】並查集 union-find(共16題)

連接:https://leetcode.com/tag/union-find/html

【128】Longest Consecutive Sequence  (2018年11月22日,開始解決hard題)node

給了一個無序的數組,問這個數組裏面的元素(能夠從新排序)能組成的最長的連續子序列是多長。本題的時間複雜度要求是 O(N).數組

本題 array 專題裏面有, 連接:https://www.cnblogs.com/zhangwanying/p/9610923.html ,用個 hashmap 能夠作到 O(N).ide

本題用 union-find 怎麼解,不知道 orz。學習

 

【130】Surrounded Regions (2019年1月31日,UF專題)this

給了個二維 grid,把裏面 O 所有變成 X,可是 邊界和邊界聯通區域內的 O 保留。spa

題解:我之前是用dfs解的。今天看了discuss高票使用UF,學習了一下。咱們把邊界上的 O 和邊界聯通區域內的 O 的座標與一個 dummy node 聯通就行了。而後遍歷 grid,若是座標與 dummy node 座標聯通,就保留成 O,否則改爲 X 3d

 1 class UF {
 2 public:
 3     UF(int size) {
 4         father.resize(size);
 5         rank.resize(size, 0);
 6         for (int i = 0; i < size; ++i) {
 7             father[i] = i;
 8         }
 9     }
10     int find(int x) {
11         return x == father[x] ? x : father[x] = find(father[x]);
12     }
13     void connect(int x, int y) {
14         int xx = find(x), yy = find(y);
15         if (xx == yy) { return; }
16         if (yy > xx) {
17             father[xx] = yy;
18         } else {
19             father[yy] = x;
20         }
21     }
22     vector<int> father;
23     vector<int> rank;  
24 };
25 class Solution {
26 public:
27     void solve(vector<vector<char>>& board) {
28         if (board.empty() || board[0].empty()) { return; }
29         const int n = board.size(), m = board[0].size();
30         UF uf(n * m + 1);
31         for (int i = 0; i < n; ++i) {
32             for (int j = 0; j < m; ++j) {
33                 if (board[i][j] == 'O') {
34                     if ((i == 0 || i == n-1 || j == 0 || j == m-1)) {
35                         uf.connect(i * m + j, n * m);
36                     } else {
37                         if (board[i-1][j] == 'O') {
38                             uf.connect(i * m + j, (i-1) * m + j);
39                         }
40                         if (board[i+1][j] == 'O') {
41                             uf.connect(i * m + j, (i+1) * m + j);
42                         }
43                         if (board[i][j-1] == 'O') {
44                             uf.connect(i * m + j, i * m + j - 1);
45                         }
46                         if (board[i][j+1] == 'O') {
47                             uf.connect(i * m + j, i * m + j  + 1);
48                         }
49                     }
50                 }
51             }
52         }
53         for (int i = 0; i < n; ++i) {
54             for (int j = 0; j < m; ++j) {
55                 if (uf.find(i * m +j) != n * m) {
56                     board[i][j] = 'X';
57                 }
58             }
59         }
60         return;
61     }
62 };
View Code

 

【200】Number of Islands  (2019年1月31日,UF專題)code

給了一個二維的grid,0 表明海, 1 的聯通塊表明島嶼,問有多少島嶼。htm

題解:和130題同樣的想法。判斷當前結點和上下左右四個結點是否是都是1,若是是的話,就聯通這兩個點。

 1 class UF {
 2 public:
 3     UF(int size) {
 4         father.resize(size);
 5         rank.resize(size, 0);
 6         for (int i = 0; i < size; ++i) {
 7             father[i] = i;
 8         }
 9     }
10     int find(int x) {
11         return x == father[x] ? x : father[x] = find(father[x]);
12     }
13     void connect(int x, int y) {
14         int xx = find(x), yy = find(y);
15         if (xx == yy) { return; }
16         if (yy < xx) {
17             father[xx] = yy;
18         } else {
19             father[yy] = xx;
20         }
21     }
22     vector<int> father;
23     vector<int> rank;  
24 };
25 class Solution {
26 public:
27     int numIslands(vector<vector<char>>& grid) {
28         if (grid.size() == 0 || grid[0].size() == 0) {
29             return 0;
30         }
31         const int n = grid.size(), m = grid[0].size();
32         UF uf(n * m);
33         for (int i = 0; i < n; ++i) {
34             for (int j = 0; j < m; ++j) {
35                 int index = i * m + j;
36                 if (grid[i][j] == '1') {
37                     if (i - 1 >= 0 && grid[i-1][j] == '1') {
38                         uf.connect(index, (i-1) * m + j);
39                     }
40                     if (i + 1 < n && grid[i+1][j] == '1') {
41                         uf.connect(index, (i+1) * m + j);
42                     }
43                     if (j - 1 >= 0 && grid[i][j-1] == '1') {
44                         uf.connect(index, i * m + j - 1);
45                     }
46                     if (j + 1 < m && grid[i][j+1] == '1') {
47                         uf.connect(index, i * m + j + 1);
48                     }
49                 }
50             }
51         }
52         int ret = 0;
53         for (int i = 0; i < n; ++i) {
54             for (int j = 0; j < m; ++j) {
55                 int index = i * m + j;
56                 if (grid[i][j] == '1' && uf.find(index) == index) {
57                     ret++;
58                 }
59             }
60         }
61         return ret;
62     }
63 };
View Code

 

【261】Graph Valid Tree (2019年1月31日,UF專題)

給了 N 個結點 和 一個邊的集合,問這個邊的集合能不能構成一棵樹。

題解:先檢查 邊集合大小是否等於 N-1, 而後用並查集檢查是否有環,沒有的話,就是樹。

 1 class UF {
 2 public:
 3     UF(int size) {
 4         father.resize(size);
 5         for (int i = 0; i < size; ++i) {
 6             father[i] = i;
 7         }
 8     }
 9     int find (int x) {
10         return x == father[x] ? x : father[x] = find(father[x]);
11     }
12     void connect (int x, int y) {
13         int xx = find(x), yy = find(y);
14         if (xx == yy) { return; }
15         if (xx < yy) {
16             father[yy] = xx;
17         } else {
18             father[xx] = yy;
19         }
20     }
21     vector<int> father;
22 };
23 class Solution {
24 public:
25     bool validTree(int n, vector<pair<int, int>>& edges) {
26         const int edgeSize = edges.size();
27         if (edgeSize != n-1) { return false; } // n 個結點的樹有 n-1 條邊
28         UF uf(n);
29         for (auto& e: edges) {
30             int u = uf.find(e.first), v = uf.find(e.second);
31             if (u == v) {
32                 return false;
33             }
34             uf.connect(e.first, e.second);
35         }
36         return true;
37     }
38 };
View Code

 

【305】Number of Islands II (2019年1月31日,UF專題)

 

【323】Number of Connected Components in an Undirected Graph (2019年2月2日,UF tag專題)

 給了 n 個結點,編號從 0 到 n-1,以及一個邊的集合。問這個無向圖裏面有多少個聯通塊。

題解:直接 uf 數聯通塊。

 1 class UF {
 2 public:
 3     UF(int size) {
 4         father.resize(size);
 5         for (int i = 0; i < size; ++i) {
 6             father[i] = i;
 7         }
 8     }
 9     int find(int x) {
10         return x == father[x] ? x : father[x] = find(father[x]);
11     }
12     void connect(int x, int y) {
13         int xx = find(x), yy = find(y);
14         if (xx == yy) { return; }
15         if (yy < xx) {
16             father[xx] = yy;
17         } else {
18             father[yy] = xx;
19         }
20     }
21     int getCount() {
22         int count = 0;
23         for (int i = 0; i < father.size(); ++i) {
24             if (father[i] == i) {
25                 count++;
26             }
27         }
28         return count;
29     }
30     vector<int> father;
31 };
32 class Solution {
33 public:
34     int countComponents(int n, vector<pair<int, int>>& edges) {
35         UF uf(n);
36         for (auto& e : edges) {
37             int u = e.first, v = e.second;
38             uf.connect(u, v);
39         }
40         return uf.getCount();
41     }
42 };
View Code

 

【547】Friend Circles (2019年2月2日,UF tag專題)

給了一個鄰接矩陣, M[i][j]  = 1表明 i,j 是朋友關係,咱們算上間接朋友關係,問這個矩陣裏面一共有幾個朋友圈子?

題解:直接用 uf 數這個圖裏面有多少聯通塊。

 1 class UF {
 2 public:
 3     UF(int size) {
 4         father.resize(size);
 5         for (int i = 0; i < size; ++i) {
 6             father[i] = i;
 7         }
 8     }
 9     int find(int x) {
10         return x == father[x] ? x : father[x] = find(father[x]);
11     }
12     void connect(int x, int y) {
13         int xx = find(x), yy = find(y);
14         if (xx == yy) { return; }
15         if (yy < xx) {
16             father[xx] = yy;
17         } else {
18             father[yy] = xx;
19         }
20     }
21     vector<int> father;
22 };
23 class Solution {
24 public:
25     int findCircleNum(vector<vector<int>>& M) {
26         const int n = M.size();
27         UF uf(n);
28         for (int i = 0; i < n; ++i) {
29             for (int j = 0; j < n; ++j) {
30                 if (M[i][j] == 1) {
31                     uf.connect(i, j);
32                 }
33             }
34         }
35         int ret = 0;
36         for (int i = 0; i < uf.father.size(); ++i) {
37             if (i == uf.father[i]) {
38                 ret++;
39             }
40         }
41         return ret;
42     }
43 };
View Code

 

【684】Redundant Connection (2018年11月22日,contest 51 模擬賽作到了)

在本題中,樹是一個無環的無向圖。輸入一個N個結點(編號是1~N)的圖,有一條邊是多餘的,把這條邊找出來。 

Example 1:
Input: [[1,2], [1,3], [2,3]]
Output: [2,3]
Explanation: The given undirected graph will be like this:
 / \
- 3

Example 2:
Input: [[1,2], [2,3], [3,4], [1,4], [1,5]]
Output: [1,4]
Explanation: The given undirected graph will be like this:
- 1 - 2
    |   |
- 3

Note:
The size of the input 2D-array will be between 3 and 1000.
Every integer represented in the 2D-array will be between 1 and N, where N is the size of the input array.

題解:我是用並查集解的。對於每一條邊的兩個結點,若是他們的爸爸不是同一個爸爸,那麼就 unoin 這兩個結點,若是他們兩個的爸爸是同一個爸爸,就說明這條邊多餘了,直接返回這條邊就好了。 

 1 class Solution {
 2 public:
 3     int findfather(int x) {
 4         return x == father[x] ? x : findfather(father[x]);
 5     }
 6     void unionNode(int x, int y) {
 7         x = findfather(x);
 8         y = findfather(y);
 9         if (x == y) { return; }
10         father[y] = x;
11     }
12     
13     vector<int> findRedundantConnection(vector<vector<int>>& edges) {
14         n = edges.size();
15         father.resize(n+1);  //redundant 0
16         for (int i = 0; i < n+1; ++i) {
17             father[i] = i;
18         }
19         vector<int> ret;
20         for (auto e : edges) {
21             int u = min(e[0], e[1]), v = max(e[0], e[1]);
22             if (findfather(v) == findfather(u)) {
23                 ret = e;
24                 break;
25             } else {
26                 unionNode(u, v);
27             }
28         }
29         return ret;
30     }
31     int n = 0;
32     vector<int> father;
33     
34 };
View Code

 

【685】Redundant Connection II (2019年2月2日,UF專題)(Hard)

給了 1~N,N個結點,N條邊的有向圖,刪除一條邊以後能造成一棵樹,返回須要刪除的那條邊,若是有多個candidate,返回數組中最後那條須要刪除的邊。

題解:本題和上一題的不一樣之處在於,上一個題只是檢測是否有環,這個題多了一些業務邏輯的判斷,主要是一個樹的一個結點不可能有兩個爸爸。

若有它有兩個爸爸,那麼這兩條邊的其中之一必定是答案。

那麼咱們先找出來看看是否存在這種狀況(一個結點有兩個爸爸),parent[i] 表明 i 結點的爸爸。若是不存在這種狀況,直接檢測是否有環就行了。

若是存在這種狀況的話,咱們先刪除這個結點和它第二個爸爸這條邊,看剩下的邊是否有環,若是有環的話,就應該返回這個結點和它第一個爸爸這條邊。

 1 class UF {
 2 public:
 3     UF(int size) {
 4         father.resize(size);
 5         for (int i = 0; i < size; ++i) {
 6             father[i] = i;
 7         }
 8     }
 9     int find(int x) {
10         return x == father[x] ? x : father[x] = find(father[x]);
11     }
12     void connect(int x, int y) {
13         int xx = find(x), yy = find(y);
14         if (xx == yy) { return; }
15         if (yy < xx) {
16             father[xx] = yy;
17         } else {
18             father[yy] = xx;
19         }
20     }
21     vector<int> father;
22 };
23 class Solution {
24 public:
25     vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
26         const int n = edges.size();
27         UF uf(n+1);
28         vector<int> parent(n+1, 0);
29         vector<int> ans1, ans2;
30         for (auto& e : edges) {
31             int p = e[0], s = e[1];
32             if (parent[s] != 0) {
33                 ans1 = {parent[s], s};
34                 ans2 = e;
35                 e[0] = e[1] = -1; //先把第二條邊刪除,而後下面用uf檢測是否有環
36                 break;
37             } else {
38                 parent[s] = p;
39             }
40         }
41         for (auto e : edges) {
42             if (e[0] < 0 && e[1] < 0) { continue; }
43             int u = uf.find(e[0]), v = uf.find(e[1]);
44             if (u == v) { //若是說在刪除第二條邊的狀況下,有環,若是有第一條邊,就返回第一條邊,否則返回第二條邊
45                 if (!ans1.empty()) {return ans1;}
46                 return e;
47             }
48             uf.connect(e[0], e[1]);
49         }
50         return ans2;
51     }
52 };
View Code

 

【721】Accounts Merge 

【737】Sentence Similarity II 

【765】Couples Holding Hands 

【778】Swim in Rising Water 

【803】Bricks Falling When Hit 

【839】Similar String Groups 

【928】Minimize Malware Spread II

相關文章
相關標籤/搜索