[路飞]_685. 冗余连接 II

139 阅读1分钟

题目路径

题目描述

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

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

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

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

示例 1:

image.png

输入: edges = [[1,2],[1,3],[2,3]]
输出: [2,3]

示例 2:

image.png

输入: edges = [[1,2],[2,3],[3,4],[4,1],[1,5]]
输出: [4,1]

解题思路

  • 并查集模板代码
class UnionSet {
    constructor (n) {
        this.parent = new Array(n).fill(0).map((value, index) => index);
    }
    get (x) {
        return this.parent[x] = (this.parent[x] == x ? x : this.get(this.parent[x]));
    }
    merge (a, b) {
        this.parent[this.get(a)] = this.get(b);
    }
}

代码

let findRedundantDirectedConnection = (edges) => {
    let nodeNum = edges.length; // 获取边的长度,就是节点的个数
    let uf = new UnionSet(nodeNum + 1); // 根据节点的个数构建并查集,加1避免它从0开始
    let parent = []; // 怎么记录产生了两个父节点,整一个数组,记录每一个节点的父节点是多少
    for(let i = 1;i <= (nodeNum + 1); i++){
        parent[i] = i; // 做一个初始化
    }

    let conflict = -1; // 来记录是否产生了双重父节点的情况
    let cycle = -1; // 来记录是否产生了环路
    for(let i in edges) {
        let edge = edges[i];
        let node1 = edge[0], node2 = edge[1]; // 拿两个节点
        if(parent[node2] != node2) { // node2这个节点有两个父节点
            conflict = i; // 这是第几组数据,把他拿下来
        } else { // 否者就是没有父节点,就把他们连起来
            parent[node2] = node1;
            if(uf.get(node1) == uf.get(node2)) { // 产生环路
                cycle = i;
            } else {
                uf.merge(node1, node2); // 两种情况都没有,就给
            }
        }
    }
    if(conflict < 0) { // 没有双重父节点产生,就把环路给记录下来
        // 只有环
        return edges[cycle];
    } else { // 有双重父节点产生
        let conflictEdge = edges[conflict];
        // 有两个入度的店,此时判断有无环
        if(cycle >= 0) {
            return [parent[conflictEdge[1]], conflictEdge[1]]
        } else {
            return conflictEdge;
        }
    }
};