• 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节点的层数。

    该数据结构,用于,

    • find:查找某个顶点的root点
      • ♻️ 优化:将所有子节点的parent都直接指向root,以后的find算法复杂度=O(1)。
    • merge:合并任意两个顶点(位于不联通的tree)的root,成为一个联通图。
      • ♻️ 优化:为了find的复杂度趋紧->O(1),我们尽量使得merge出的树rank(层数)尽量的小。
      • 因此,在merge时,比较两顶点root的rank,使用大的作为新的root
      • 当两个顶点rank相同,只能任选其一作为新的root,新root的rank++;

    可查找:

    • 两个顶点,是否在一个联通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 };
  • 相关阅读:
    NOIP2009-2018简要题解
    luogu P5023 填数游戏
    Java桌面精灵基础——swing类的使用与关键代码
    c信号处理程序以及setjmp函数longjmp函数的简单应用
    mmapcopy函数的编写
    nm命令的学习以及可执行文件中的段
    关于C中数组和指针的一点理解
    写一个简单的lisp解释器(1)
    House Robber
    SICP_3.31
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/13448395.html
Copyright © 2020-2023  润新知