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

 

posted @ 2020-08-06 19:21  habibah_chang  阅读(116)  评论(0编辑  收藏  举报