Redundant Connection II

In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) for which all other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which has no parents.

The given input is a directed graph that started as a rooted tree with N nodes (with distinct values 1, 2, ..., N), with one additional directed edge added. The added edge has two different vertices chosen from 1 to N, and was not an edge that already existed.

The resulting graph is given as a 2D-array of edges. Each element of edges is a pair [u, v] that represents a directed edge connecting nodes u and v, where u is a parent of child v.

Return an edge that can be removed so that the resulting graph is a rooted tree of N nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array.

Example 1:

Input: [[1,2], [1,3], [2,3]]
Output: [2,3]
Explanation: The given directed graph will be like this:
  1
 / \
v   v
2-->3

Example 2:

Input: [[1,2], [2,3], [3,4], [4,1], [1,5]]
Output: [4,1]
Explanation: The given directed graph will be like this:
5 <- 1 -> 2
     ^    |
     |    v
     4 <- 3

参考:https://leetcode.com/problems/redundant-connection-ii/discuss/375720/Java-UnionFind 

https://www.youtube.com/watch?v=lnmJT5b4NlM

思路: https://ibb.co/Ttp49DG 

这题分三种情况讨论:

1. 如果没有任何node有两个parent,也就是首尾相连环,那么问题转换为Redundant Connection I.

2. 如果没有环,但是有node有两个parent

3. 如果有环,而且有node有两个parent

1.的话,直接按照connection I的方法做,返回最后一个node是相等的edge;

2.如果没有环,那么返回第二个边;

3.如果有环,我把第二个边去掉了,但是还是有环,那么去掉环里面的第一条边;

这题比较tricky的地方是:用parent数组来记录parent,如果有两个parent,则可以把前后两条边记录下来,同时把第二条边去掉(变成-1,-1);然后做union find,如果还是发现环了,那么如果第一条边不存在,证明是首尾相连,直接返回edge,如果第一条边存在,那么就返回第一条边(因为我把第二条边之前已经变为-1,-1了,那么还存在环,那么必然是第一条边出问题了。如果没有找到环,那么就是我去掉的第二条边是问题所在。

class Solution {
    private class UnionFind {
        public int[] father;
        public int count;
        public UnionFind(int n) {
            this.father = new int[n + 1];
            for(int i = 0; i <= n; i++) {
                father[i] = i;
            }
            this.count = n;
        }
        
        public int find(int x) {
            int j = x;
            while(father[j] != j) {
                j = father[j];
            }
            
            //path compression;
            while(x != j) {
                int fx = father[x];
                father[x] = j;
                x = fx;
            }
            return j;
        }
        
        public void union(int a, int b) {
            int root_a = find(a);
            int root_b = find(b);
            if(root_a != root_b) {
                father[root_a] = root_b;
                count--;
            }
        }
    }
    
    public int[] findRedundantDirectedConnection(int[][] edges) {
        if(edges == null || edges.length == 0 || edges[0].length == 0) {
            return new int[0];
        }
        int n = edges.length;
        UnionFind uf = new UnionFind(n);
        int[] res1 = new int[2];
        int[] res2 = new int[2];
        int[] parent = new int[n + 1];
        
        for(int i = 0; i < edges.length; i++) {
            int u = edges[i][0];
            int v = edges[i][1];
            
            if(parent[v] > 0) {
                res1[0] = parent[v];
                res1[1] = v;
                
                res2[0] = u;
                res2[1] = v;
                
                //把第二条边去掉;
                edges[i][0] = -1;
                edges[i][1] = -1;
            }
            parent[v] = u;
        }
        
        for(int i = 0; i < edges.length; i++) {
            int u = edges[i][0];
            int v = edges[i][1];
            
            if(u == -1 && v == -1) {
                continue;
            }
            
            if(uf.find(u) != uf.find(v)) {
                uf.union(u, v);
            } else {
                // uf.find(u) == uf.find(v);
                // 如果找到环了,而且res1 不为空,也就是有第一条边和第二条边的记录;
                // 我已经把第二条边remove掉了,还是有环,那么必定是第一条边,直接返回第一条边;
                if(res1[0] > 0) {
                    return res1;
                } else {
                    // 如果找到环了,但是第一条边和第二条边的记录没有,那么就是没有node有两个parent,
                    // 那么问题就是connection I, 也就是返回这个edge就可以了;
                    return edges[i];
                }
            }
        }
        // 如果去掉了第二边,没有找到环,那么就是第二边是问题所在;
        return res2;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值