[路飞][LeetCode]685_冗余连接 II

223 阅读2分钟

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

看一百遍美女,美女也不一定是你的。但你刷一百遍算法,知识就是你的了~~

谁能九层台,不用累土起!

题目地址

题目

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

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

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

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

示例 1:

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

示例 2:

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

提示:

  • n == edges.length
  • 3 <= n <= 1000
  • edges[i].length == 2
  • 1 <= ui, vi <= n

解题思路

  • 这题我们使用并查集
  • 我们先查询是否存在某个点入度为2
  • 如果不存在这个点,那么我们只需要当 684_冗余连接 来做就行了,只需要返回冗余边
  • 如果存在这个点,我们倒序遍历edges
  • 找出能删除后组成不了环的边,将其返回

解题代码

var findRedundantDirectedConnection = function(edges) {
    const n = edges.length
    let union = new Union(n)
    let inputPoint=new Array(n+1).fill(0)
    let hasTwoPoint = -1
    for(let i=0;i<n;i++){
        let b = edges[i][1]
        inputPoint[b]++
        if(inputPoint[b]==2) {
            hasTwoPoint = b
            break
        }
    }

    
    if(hasTwoPoint==-1){ // 不存在重复连接的节点
        for(let [a,b] of edges){
            if(!union.merge(a,b)) {
                return [a,b]
            }
        }
    }

    for(let i = n-1;i>=0;i--){
        if(edges[i][1]==hasTwoPoint){
          const uf = new Union(n);
          if(uf.isCircle(edges,edges[i])==null){ // 没有环,说明删除的是对的
              return edges[i]
          }
        }
    }
    return
};

class Union {
    constructor(n){
        this.arr = new Array(n).fill(0).map((v,i)=>i) // 初始化
    }

    find(i){ // 查找根节点
        if(this.arr[i]==i) return i
        return this.find(this.arr[i])
    }

    connect(a,b){ // 判断是否连接
        return this.find(a) == this.find(b)
    }

    merge(a,b){ // 合并
        if(this.connect(a,b)) return false
        this.arr[this.find(a)] = this.find(b)
        return true
    }

    isCircle(edges,circle){  // 用于判断是否有环
        for(let i=0;i<edges.length;i++){
            if (edges[i]==circle) { // 剔除要删除的边
                continue
            }
            if (!this.merge(edges[i][0],edges[i][1])) {
                return edges[i]
            }
        }
        return null;
    }
}

如有任何问题或建议,欢迎留言讨论!