684. Redundant Connection
问题:
我们称:不存在回环的无向图为tree
那么给定一组edge [u,v],定义从顶点u到v的连线,构成无向图。
求最后一个多余出来的[u,v],使得出现了回环。(若没有这个连线,则可形成tree)
Example 1: Input: [[1,2], [1,3], [2,3]] Output: [2,3] Explanation: The given undirected graph will be like this: 1 / \ 2 - 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: 5 - 1 - 2 | | 4 - 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.
解法:并查集(Disjoint Set)
使用的数据结构:
- parent[x]:每一个点x的root节点。
- rank[x]:每一个节点x作为root节点的树层数。
- ✳️ 因此,只有root节点拥有该属性,且只有在merge动作,才会需要更新该值
该数据结构,用于,
- find:查找某个顶点的root点
- ♻️ 优化:将所有子节点的parent都直接指向root,以后的find算法复杂度=O(1)。
- merge:合并任意两个顶点(位于不联通的tree)的root,选择其一为新root,成为一个联通图。
- ♻️ 优化:为了find的复杂度趋紧->O(1),我们尽量使得merge出的树rank(层数)尽量的小。 因此,在merge时,比较两顶点root的rank(R vs r),使用大(R)的作为新的root
- ✳️ R>r -> R>=r+1,因此,新root的rank:R保持不变
- 当两个顶点rank相同(r==R),只能任选其一作为新的root:R
- 由于原本的一个root:r变成子,那么它所在的树,R=max(r+1, R)=max(r+1,r)=r+1 ;
可查找:
- 两个顶点,是否在一个联通tree上:find(x)?=find(y)
- 两个顶点所在连通图上是否构成环:merge?=false
- 已经联通的两个点,再进行merge(联通操作),会失败。
Disjoint Set的类实现:
1 class DisjoinSet { 2 public: 3 DisjoinSet(int n):parent(n), rank(n, 0) { 4 for(int i=0; i<n; i++) parent[i]=i; 5 } 6 int find(int i) { 7 if(parent[i] != i) { 8 parent[i] = find(parent[i]); 9 } 10 return parent[i]; 11 } 12 // true: no cycle. false: cycle exist 13 bool merge(int x, int y) { 14 int x_root = find(x); 15 int y_root = find(y); 16 if(x_root == y_root) return false; 17 if(rank[x_root] < rank[y_root]) { 18 parent[x_root] = y_root; 19 } else if(rank[y_root] < rank[x_root]) { 20 parent[y_root] = x_root; 21 } else { 22 parent[y_root] = x_root; 23 rank[x_root]++; 24 } 25 return true; 26 } 27 28 private: 29 vector<int> parent; 30 vector<int> rank; 31 };
本问题,则轮询给定的连接边,
逐一进行merge
知道merge返回false,
则将当前的边,计入结果返回。
代码参考:
1 class Solution { 2 public: 3 vector<int> findRedundantConnection(vector<vector<int>>& edges) { 4 vector<int> res; 5 DisjoinSet DS(edges.size()); 6 for(vector<int> ed: edges) { 7 if(DS.merge(ed[0]-1, ed[1]-1)==false) { 8 return {ed[0], ed[1]}; 9 } 10 } 11 return res; 12 } 13 };