連接: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 };
【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 };
【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 };
【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 };
【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 };
【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 };
【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 };
【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