150NeetCode 150

89.Redundant Connection

MediumGraphs ยท 10/19

Problem

A tree with n nodes labelled 1 to n had one extra edge added, creating a graph with n edges. The extra edge connects two different nodes and is not a duplicate of an existing edge. The graph is given as edges, where edges[i] = [a, b] is an undirected edge.

Return an edge that can be removed so the remaining graph is a tree of n nodes. If there are multiple answers, return the one that appears last in edges.

Examples

Input:  edges = [[1,2],[1,3],[2,3]]
Output: [2,3]
Explanation: 1-2-3-1 is a triangle. Any of its three edges could go; [2,3] is the last one listed.
Input:  edges = [[1,2],[2,3],[3,4],[1,4],[1,5]]
Output: [1,4]
Explanation: The cycle is 1-2-3-4-1. Of its edges, [1,4] appears last in the input. [1,5] is not on the cycle.

Constraints

  • n == edges.length
  • 3 <= n <= 1000
  • edges[i].length == 2
  • 1 <= a < b <= n
  • No repeated edges; the given graph is connected

๐Ÿ’ก Key Insight

A tree plus one edge contains exactly one cycle, and the answer is the last-listed edge on it. Process edges in input order while tracking which nodes are already connected: the first edge whose two endpoints are already in the same component closes the cycle. Every cycle edge was added earlier, so this edge is precisely the last cycle edge in the input. Union-Find answers "same component?" and merges components in near-O(1) time.

Brute Force (DFS Before Each Edge)

TimeO(nยฒ)SpaceO(n)

Intuition

Build the graph one edge at a time. Before adding [u, v], run a DFS from u over the edges added so far. If v is already reachable, the new edge would create a cycle โ€” return it. Because edges are processed in order, the first such edge is the last cycle edge in the input.

Algorithm

  1. Start with an empty adjacency list for nodes 1..n.
  2. For each edge [u, v]:
    • If dfs(u, v) (with a fresh visited array) reaches v, return [u, v].
    • Otherwise add v to graph[u] and u to graph[v].
  3. Return an empty array (unreachable for valid input).

Visualization

edges = [[1,2],[2,3],[3,4],[1,4],[1,5]]

[1,2]: can 1 reach 2? no  โ†’ add
[2,3]: can 2 reach 3? no  โ†’ add
[3,4]: can 3 reach 4? no  โ†’ add
[1,4]: can 1 reach 4? 1 โ†’ 2 โ†’ 3 โ†’ 4  yes โ†’ return [1,4]

Code

java
import java.util.ArrayList;
import java.util.List;

class Solution {
    public int[] findRedundantConnection(int[][] edges) {
        int n = edges.length;
        List<List<Integer>> graph = new ArrayList<>();
        for (int i = 0; i <= n; i++) graph.add(new ArrayList<>());

        for (int[] e : edges) {
            int u = e[0], v = e[1];
            // If u can already reach v, this edge closes a cycle
            if (reachable(graph, u, v, new boolean[n + 1])) return e;
            graph.get(u).add(v);
            graph.get(v).add(u);
        }
        return new int[0];
    }

    private boolean reachable(List<List<Integer>> graph, int cur, int target, boolean[] visited) {
        if (cur == target) return true;
        visited[cur] = true;
        for (int next : graph.get(cur)) {
            if (!visited[next] && reachable(graph, next, target, visited)) return true;
        }
        return false;
    }
}

Complexity

  • Time: O(nยฒ) โ€” up to n edges, each followed by a DFS over up to n nodes and edges.
  • Space: O(n) โ€” adjacency lists, visited and recursion depth.

Complexity Comparison

Approach Time Space
Brute Force (DFS Before Each Edge) O(nยฒ) O(n)
Find the Cycle with One DFS O(n) O(n)
Union-Find O(nยทฮฑ(n)) O(n)

Common Pitfalls

  • Sizing arrays as n instead of n + 1 โ€” nodes are labelled 1..n, not 0..n-1.
  • Returning the first cycle edge found by a cycle-only DFS instead of the one that appears last in edges.
  • Comparing parent[u] == parent[v] instead of find(u) == find(v); only roots identify a set.
  • In the undirected DFS, treating the edge back to the immediate parent as a cycle.
  • Building the full graph before running the incremental check โ€” the brute force must only see edges added before the current one.