685. Redundant Connection II

这题跟684不一样的地方是这是一个有向图。
对于一个树来说,如果多了一条边的话,这条边能组成什么样子的图呢。
答案里给了是什么形式的(有环入度都有1, 有环有入度有为2的点, 无环有入度为2)。
不过答案里是直接给的这几种形式,看的云里雾里的, 也很难记住。
我们还是仔细分析一下。

  1. 这 条多的边可以是从下向上的, 这样就可能组成环, 也可能不组环。

    • 如果从下向上指向了root, 则有环,没有入度为0的点, 只有入度为1的点。
    • 如果从下向上指向了某个非root的父亲节点, 则有环,有入度为 0 和 入度2的点
    • 如果从下向上指向了别的子树的节点,则没有环,有入度为 0 有入度为 2的点 。
  2. 这条多的边也可以是从上向下的,这样一条边就有两个root。
    -如果从上向下, 则没有环,有入度为 0 有入度为 2的点。

所以策略是这样子,

  • 先看没有没有入度为2的点。
    -- 如果没有入度为2的点,则有环,用union find找
    -- 如果有入度为2的点,则看有没有环。
    这里巧妙的一点是 默认第二个出现的是背锅的,
    所以看一下把第二个edge扔掉一切就正常了那就扔第二个,如果扔了第二个还有环的话那肯定就是第一个。

如果没有环我肯定扔第 二个, 如果有环的话,要挑那个环上的扔。至于怎么判断哪个在环上,扔第二个,看还有没有环,还有环的话那就是扔错了。

这样的话是不是用更容易理解了, 分析起来也容易了。

class Solution {
    public int[] findRedundantDirectedConnection(int[][] edges) {
        int N = edges.length;
        ArrayList[] graph = new ArrayList[N + 1];
        ArrayList[] parent = new ArrayList[N + 1];
        int[][] candidates = null;
        for (int i = 0; i <= N; i++) graph[i] = new ArrayList<>();
        for (int i = 0; i <= N; i++) parent[i] = new ArrayList<>();
        for (int[] edge : edges) {
            int a = edge[0], b = edge[1];
            
            if (parent[b].size() == 1) {
                candidates = new int[][] {{parent[b].get(0), b}, {a,b}};
            } else {
                graph[a].add(b);
                parent[b].add(a);
            }
        }
        if (candidates == null) return findRedundantConnectionI(edges, null);
        int[] candidate = findRedundantConnectionI(edges, candidates[1]);
        if (candidate != null) return candidates[0];
        return candidates[1];
    }
    private int[] findRedundantConnectionI(int[][] edges, int[] deleteEdge) {
        UnionFind uf = new UnionFind(edges.length + 1);
        for (int[] edge : edges) {
            if (Arrays.equals(edge, deleteEdge)) continue;
            if (!uf.union(edge[0], edge[1])) return edge;
        }
        return null;
    }
}
class UnionFind{
    int[] ids;
    int[] weights;
    public UnionFind(int n) {
        ids = new int[n];
        weights = new int[n];
        for (int i = 0; i < n; i++) {
            ids[i] = i;
            weights[i] = 1;
        }
    }
    public int root(int id) {
        if (ids[id] != id) ids[id] = root(ids[id]);
        return ids[id];
    }
    public boolean union(int id1, int id2) {
        int root1 = root(id1), root2 = root(id2);
        if (root1 == root2) return false;
        if (weights[root1] >= weights[root2]) {
            weights[root1] += weights[root2];
            ids[root2] = root1;
        } else {
            weights[root2] += weights[root1];
            ids[root1] = root2;
        }
        return true;
    }
}

你可能感兴趣的:(685. Redundant Connection II)