Skip to content

685. Redundant Connection II

Description

In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) for which all other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which has no parents.

The given input is a directed graph that started as a rooted tree with n nodes (with distinct values from 1 to n), with one additional directed edge added. The added edge has two different vertices chosen from 1 to n, and was not an edge that already existed.

The resulting graph is given as a 2D-array of edges. Each element of edges is a pair [ui, vi] that represents a directed edge connecting nodes ui and vi, where ui is a parent of child vi.

Return an edge that can be removed so that the resulting graph is a rooted tree of n nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array.

 

Example 1:

Input: edges = [[1,2],[1,3],[2,3]]
Output: [2,3]

Example 2:

Input: edges = [[1,2],[2,3],[3,4],[4,1],[1,5]]
Output: [4,1]

 

Constraints:

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

Solutions

Solution 1: Union-Find

According to the problem description, for a rooted tree, the in-degree of the root node is $0$, and the in-degree of other nodes is $1$. After adding an edge to the tree, there can be the following three scenarios:

  1. The added edge points to a non-root node, and the in-degree of that node becomes $2$. In this case, there is no directed cycle in the graph:

       1
      / \
     v   v
     2-->3
    
  2. The added edge points to a non-root node, and the in-degree of that node becomes $2$. In this case, there is a directed cycle in the graph:

       1
       |
       v
       2 <--> 3
    
  3. The added edge points to the root node, and the in-degree of the root node becomes $1$. In this case, there is a directed cycle in the graph, but there are no nodes with an in-degree of $2$.

        1
        /^
       v  \
       2-->3
    

Therefore, we first calculate the in-degree of each node. If there exists a node with an in-degree of $2$, we identify the two edges corresponding to that node, denoted as $\textit{dup}[0]$ and $\textit{dup}[1]$. If deleting $\textit{dup}[1]$ results in the remaining edges not forming a tree, then $\textit{dup}[0]$ is the edge that needs to be deleted; otherwise, $\textit{dup}[1]$ is the edge that needs to be deleted.

If there are no nodes with an in-degree of $2$, we traverse the array $\textit{edges}$. For each edge $(u, v)$, we use the union-find data structure to maintain connectivity between nodes. If $u$ and $v$ are already connected, it indicates that there is a directed cycle in the graph, and the current edge is the one that needs to be deleted.

The time complexity is $O(n \log n)$, and the space complexity is $O(n)$, where $n$ is the number of edges.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution:
    def findRedundantDirectedConnection(self, edges: List[List[int]]) -> List[int]:
        def find(x: int) -> int:
            if p[x] != x:
                p[x] = find(p[x])
            return p[x]

        n = len(edges)
        ind = [0] * n
        for _, v in edges:
            ind[v - 1] += 1
        dup = [i for i, (_, v) in enumerate(edges) if ind[v - 1] == 2]
        p = list(range(n))
        if dup:
            for i, (u, v) in enumerate(edges):
                if i == dup[1]:
                    continue
                pu, pv = find(u - 1), find(v - 1)
                if pu == pv:
                    return edges[dup[0]]
                p[pu] = pv
            return edges[dup[1]]
        for i, (u, v) in enumerate(edges):
            pu, pv = find(u - 1), find(v - 1)
            if pu == pv:
                return edges[i]
            p[pu] = pv
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Solution {
    private int[] p;

    public int[] findRedundantDirectedConnection(int[][] edges) {
        int n = edges.length;
        int[] ind = new int[n];
        for (var e : edges) {
            ++ind[e[1] - 1];
        }
        List<Integer> dup = new ArrayList<>();
        p = new int[n];
        for (int i = 0; i < n; ++i) {
            if (ind[edges[i][1] - 1] == 2) {
                dup.add(i);
            }
            p[i] = i;
        }
        if (!dup.isEmpty()) {
            for (int i = 0; i < n; ++i) {
                if (i == dup.get(1)) {
                    continue;
                }
                int pu = find(edges[i][0] - 1);
                int pv = find(edges[i][1] - 1);
                if (pu == pv) {
                    return edges[dup.get(0)];
                }
                p[pu] = pv;
            }
            return edges[dup.get(1