Redundant Connection
You are given a graph that started as a tree with n nodes labeled 1 to n, with one additional edge added. Return an edge that can be removed so that the resulting graph is a tree of n nodes. If there are multiple answers, return the answer that occurs last in the input. Process edges in order, and before unioning two nodes call find on both. The first edge whose endpoints already share a root is the redundant one.
Constraints
- n == edges.length
- 3 ≤ n ≤ 1000
- edgesi.length == 2
- 1 ≤ ai < bi ≤ edges.length
- ai != bi
Example
edges = [[1,2],[1,3],[2,3]][2,3]Explanation Edges [1,2] and [1,3] build the tree. Edge [2,3] closes a cycle back to node 1.
Union edges in order, stop at the first repeat root
Edge [1, 2]: different roots, so union them — node 1 now points at node 2.
What happens in this step
edge [1, 2] find(1) → 1 find(2) → 2 roots differ → union: parent[1] = 2 parent array (index 1..3): [1, 2, 3] → [2, 2, 3] Nodes 1 and 2 merge, with root 2 now representing both.
Steps to visualize
- The row has one cell per node (nodes are labelled 1, 2, 3). Each cell shows that node's current parent; a node pointing at itself is a root.
- Give every node its own group, so each node starts as its own parent.
- For each edge [a, b] in order, compare find(a) and find(b); the frame covers the two nodes of that edge.
- If they already match, this edge is redundant — return it immediately.
- Otherwise union a and b and continue to the next edge.
Walk through the code
Same walkthrough, now with the code. Press Next to move one step and watch which lines run.
Edge [1, 2]: different roots, so union them — node 1 now points at node 2.
What happens in this step
edge [1, 2] find(1) → 1 find(2) → 2 roots differ → union: parent[1] = 2 parent array (index 1..3): [1, 2, 3] → [2, 2, 3] Nodes 1 and 2 merge, with root 2 now representing both.
Solution
function findRedundantConnection(edges) {
const n = edges.length;
const parent = Array.from({ length: n + 1 }, (_, i) => i);
function find(x) {
while (parent[x] !== x) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
for (const [a, b] of edges) {
const rootA = find(a);
const rootB = find(b);
if (rootA === rootB) {
return [a, b];
}
parent[rootA] = rootB;
}
return [];
}- Time
- O(n · α(n))
- Space
- O(n)
Test cases
| Input | Expected | Covers |
|---|---|---|
edges = [[1,2],[1,3],[2,3]] | [2,3] | example from the docstring |
edges = [[1,2],[2,3],[3,4],[1,4],[1,5]] | [1,4] | the redundant edge appears in the middle of the list |
edges = [[1,2],[2,3],[3,1]] | [3,1] | smallest possible cycle, three nodes |
edges = [[1,4],[3,4],[1,3],[1,2]] | [1,3] | the redundant edge is found before the last edge in the list is even reached |
edges = [[1,2],[1,3],[1,4],[3,4]] | [3,4] | every earlier node attaches directly to node 1 before the cycle closes |
edges = [[1,2],[2,3],[3,4],[4,1]] | [4,1] | a longer cycle spanning all four nodes |