685. 冗余连接 II​​​​​​​

685. 冗余连接 II

在本问题中,有根树指满足以下条件的有向图。该树只有一个根节点,所有其他节点都是该根节点的后继。每一个节点只有一个父节点,除了根节点没有父节点。

输入一个有向图,该图由一个有着N个节点 (节点值不重复1, 2, ..., N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。

结果图是一个以边组成的二维数组。 每一个边 的元素是一对 [u, v],用以表示有向图中连接顶点 u 和顶点 v 的边,其中 u 是 v 的一个父节点。

返回一条能删除的边,使得剩下的图是有N个节点的有根树。若有多个答案,返回最后出现在给定二维数组的答案。

示例 1:

输入: [[1,2], [1,3], [2,3]]
输出: [2,3]
解释: 给定的有向图如下:
  1
 / \
v   v
2-->3
示例 2:

输入: [[1,2], [2,3], [3,4], [4,1], [1,5]]
输出: [4,1]
解释: 给定的有向图如下:
5 <- 1 -> 2
     ^         |
     |         v
     4  <-   3

 

基本思路1:试着对一棵树添加一条边,很容易得到一个入度为2的节点,而删除该节点为末端节点的两边之一,可以得到正常结果;但是,考虑一种特殊的情况,退化成链表的树(极限一点)首尾形成环时的情况要特殊考虑。关于判断是否形成环时,才用的是并查集的方法。

基本思路2:一棵树最主要的特点是根节点只有一个,且没有父节点(环破坏了这点),另外,每个节点(除了根节点),都只有一个父节点(即入度为1)。另,在一棵树上添加一条边,则势必形成一个无向图,并查集就出现了。以此来反推上面的情况。

 

class Solution {
private:
vector<int> parent,psize;
public:
    int find(int x){
        if(x!=parent[x])
            parent[x]=find(parent[x]);

        return parent[x];
    }

    void Un(int x,int y){  //相连的节点挂在同一棵树上
        int rootp=find(x);
        int rootq=find(y);
        if(rootp!=rootq){
            if(psize[rootp]>psize[rootq]){
                psize[rootp]+=psize[rootq];
                parent[rootq]=rootp;
            }
            else{
                psize[rootq]+=psize[rootp];
                parent[rootp]=rootq;
            }
        }
    }

    bool IsConnect(int x,int y){
        int rootp=find(x);
        int rootq=find(y);
        return rootp==rootq;
    }

    void init(int n){
        parent.resize(n,0);
        psize.resize(n,0);
        for(int i=0;i<n;i++){
            parent[i]=i;
            psize[i]=1;
        }
    }
    bool isTreeAfterRemoveEdge(vector<vector<int>> &edges,int deleteEdg){
        int n=edges.size();
        init(n+1);
        for(int i=0;i<n;i++){
            if(i==deleteEdg)
                continue;
            if(IsConnect(edges[i][0],edges[i][1])){
                return false;
            }
            else{
                Un(edges[i][0],edges[i][1]);
            }
        }
        return true;
    }
    vector<int> FromCircleGetRemoveEdg(vector<vector<int>> &edges){
        int n=edges.size();
        init(n+1);
        for(int i=0;i<n;i++){
            if(IsConnect(edges[i][0],edges[i][1])){
                return {edges[i][0],edges[i][1]};
            }
            else{
                Un(edges[i][0],edges[i][1]);
            }
        }
        return {};
    }
    vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
        int n=edges.size();
        init(n+1);
        vector<int> inDegree(n+1,0);
        vector<int> vec2;
        for(int i=0;i<n;i++){
            inDegree[edges[i][1]]++;
        }

        for(int i=0;i<n;i++){
            if(inDegree[edges[i][1]]==2)  //入度为2的情况
                vec2.push_back(i);
        }
        if(vec2.size()>0){
            if(isTreeAfterRemoveEdge(edges,vec2[1])){  //之所以要先1,是对应题目要求多个答案时返回最后一个。
                return edges[vec2[1]];  //防止存在同时是环,也是indegre==2的情况
            }
            else{
                return edges[vec2[0]];
            }
        }



        return FromCircleGetRemoveEdg(edges);  //从左到右开始遍历边,原因同上
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值