[路飞]_冗余连接II

「这是我参与2022首次更文挑战的第39天,活动详情查看:2022首次更文挑战

leetcode-685 冗余连接II

题目介绍

原题目请见上方链接

解题思路

该题目是在一棵正常的树上面加了一条边,我们先来看看在一棵树上加上一条有向边会出现什么情况

  1. 第一种情况是多余的边指向的节点本来已经有了一个父节点,添加了一条边之后这个节点有两个父节点,导致冲突

演示文稿 4(9).gif

  1. 第二种情况是多余的边指向了根节点,导致树中的每个节点都存在一个父节点,从而形成了一个环

演示文稿 4(8).gif

  1. 第三种情况是前面两种情况的结合体,多余的边指向一个节点之后,既形成了环又有一个节点同时存在两个父节点

演示文稿 4(10).gif

在一棵完整的树上添加一条有向边无非上述三种情况,接下来说一下这三种情况怎么破局:

  1. 对于第一种情况,我们先按题目的给出的边的顺序进行节点间的连接(记录每个节点的父节点),当一条边指向的节点已经存在了父节点,那就说明这条边是冲突的边,直接返回这条边即可
  2. 对于第二种情况,我们先利用并查集的思想,将题目给出的每一条边的节点连通起来,当遍历到一条边,其两头的节点已经存在于同一个集合中,那就说明这条边是形成环的边,并且是最后一条边,因此我们直接返回这条边即可
  3. 对于第三种情况,需要将前面的两种情况结合起来。
  • 首先我们遍历每一条边,如果这条边不是冲突的边,我们就将这条边两头的节点进行连通
  • 如果是冲突的边,就将这条边的下标记录起来,然后不更新当前节点的父节点,继续判断后面的边,出现了形成环的边时,记录当前成环的边的下标
  • 这时因为冲突的边没有连上,而又出现了成环的边,说明附加边就是图中红色的这条边,怎么找到这条边呢?(成环的边的父节点的父节点 -> 成环的边的父节点的这条边)

1645866481(1).png

解题代码

var findRedundantDirectedConnection = function(edges) {
    const unionSet = new UnionSet(edges.length + 1)
    // 用于记录每个节点的父节点
    const father = []
    for (let i = 1; i <= edges.length; i++) {
        father[i] = i
    }

    // 记录冲突的边的下标
    let conflict = -1
    // 记录成环的边的下标
    let cycle = -1
    for (let i = 0; i < edges.length; i++) {
        const node1 = edges[i][0], node2 = edges[i][1]
        if (father[node2] !== node2) {
            // 如果出现冲突的边,只记录下标,不进行连接
            conflict = i
        } else {
            // 如果不是冲突的边,先记录父节点,然后判断是否成环
            father[node2] = node1
            if (unionSet.get(node1) === unionSet.get(node2)) {
                cycle = i
            } else {
                unionSet.merge(node1, node2)
            }
        }
    }
    
    if (conflict === -1) {
        // 如果没有冲突的边,成环的边就是附加边
        return edges[cycle]
    } else {
        if (cycle > -1) {
            // 如果既有成环的边又有附加的边,那么就是 `成环的边的父节点的父节点 -> 成环的边的父节点` 这条边
            return [father[edges[conflict][1]], edges[conflict][1]]
        } else {
            // 如果没有成环的边,那么冲突的边就是附加边
            return edges[conflict]
        }
    }
};

// 并查集
class UnionSet{
    constructor(n) {
        this.fa = []
        this.size = []
        for (let i = 0; i < n; i++) {
            this.fa[i] = i
            this.size[i] = 1
        }
    }

    get(v) {
        if (this.fa[v] === v) return v
        const root = this.get(this.fa[v])
        this.fa[v] = root
        return root
    }

    merge(a, b) {
        const ra = this.get(a), rb = this.get(b)
        if (ra === rb) return 
        if (this.size[ra] < this.size[rb]) {
            this.fa[ra] = rb
            this.size[rb] += this.size[ra]
        } else {
            this.fa[rb] = ra
            this.size[ra] += this.size[rb]
        }
    }
}
复制代码

猜你喜欢

转载自juejin.im/post/7068945075199279118