685. 冗余连接 II

169 阅读1分钟

题目描述

leetcode-cn.com/problems/re…

解题思路

对于冗余连接,共有 3 种情况:

一个节点有两个 parent,

image.png

移除第二个边

有环

image.png

移除一个边

环 + 两个 parent

image.png

移除 [2 ,3]

详细解释第三种

可以看到,我们总是根据题意去移除第二个边,那么如果在移除这条边后发现,剩下的边会形成环,我们就应该移除第一个边

If [[1, 2], [2, 3], [4, 3], [3, 1]], [2, 3] 在 [4, 3] 之前, 移除 [4,3], union [1, 2], [2, 3], [3, 1], 有环 -- 应移除的其实是 [2, 3].
If [[1, 2], [4, 3], [2, 3], [3, 1]], [4, 3] 在 [2, 3] 之前, 移除 [2, 3], union [1, 2], [4, 3], [3, 1], 没有环 -- 移除 [2, 3] 是正确的.

代码

function findRedundantDirectedConnection(edges) {
  let numNodes = edges.length,
    edgeRemoved = -1,
    edgeMakesCycle = -1
  const parent = new Array(numNodes + 1).fill(0)

  for (let i = 0; i < numNodes; i++) {
    const u = edges[i][0]
    const v = edges[i][1]
    if (parent[v] != 0) {
      /* Assume we removed the second edge. */
      edgeRemoved = i
      break
    } else parent[v] = u
  }

  const uf = new UnionFind(numNodes)
  for (let i = 0; i < numNodes; i++) {
    if (i == edgeRemoved) continue
    const u = edges[i][0]
    const v = edges[i][1]
    if (!uf.union(u, v)) {
      edgeMakesCycle = i
      break
    }
  }

  /* Handle with the cyclic problem only. */
  if (edgeRemoved == -1) {
    return edges[edgeMakesCycle]
  }

  /* Handle with the cyclic problem when we remove the wrong edge. */
  if (edgeMakesCycle != -1) {
    const v = edges[edgeRemoved][1]
    const u = parent[v]
    return [u, v]
  }

  /* CHandle with the cyclic problem when we remove the right edge. */
  return edges[edgeRemoved]
}

class UnionFind {
  constructor(n) {
    this.parent = new Array(n + 1)
    this.rank = new Array(n + 1)
    for (let i = 1; i < n + 1; i++) {
      this.parent[i] = i
      this.rank[i] = 1
    }
  }

  find = (x) => {
    const parent = this.parent
    const find = this.find
    if (parent[x] == x) return x
    return (parent[x] = find(parent[x]))
  }

  union = (x, y) => {
    const rootX = this.find(x)
    const rootY = this.find(y)
    const parent = this.parent
    const rank = this.rank

    if (rootX == rootY) return false
    if (rank[rootX] < rank[rootY]) {
      parent[rootX] = rootY
      rank[rootY] += rank[rootX]
    } else {
      parent[rootY] = rootX
      rank[rootX] += rank[rootY]
    }
    return true
  }
}