Redundant Connection

Problem Statement

You are given a connected undirected graph with n nodes labeled from 1 to n. Initially, it contained no cycles and consisted of n-1 edges.

We have now added one additional edge to the graph. The edge has two different vertices chosen from 1 to n, and was not an edge that previously existed in the graph.

The graph is represented as an array edges of length n where edges[i] = [ai, bi] represents an edge between nodes ai and bi in the graph.

Return an edge that can be removed so that the graph is still a connected non-cyclical graph. If there are multiple answers, return the edge that appears last in the input edges.

Example 1:

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

Example 2:

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

Constraints:

  • n == edges.length
  • 3 <= n <= 100
  • 1 <= edges[i][0] < edges[i][1] <= edges.length
  • There are no repeated edges and no self-loops in the input.

You should aim for a solution as good or better than O(V + E) time and O(V) space, where V is the number vertices and E is the number of edges in the graph.

You should aim for a solution as good or better than O(V + E) time and O(V) space, where V is the number vertices and E is the number of edges in the graph.

Hint 1

There will be only one edge that creates the cycle in the given problem. Why? Because the graph is initially acyclic, and a cycle is formed only after adding one extra edge that was not present in the graph initially. Can you think of an algorithm that helps determine whether the current connecting edge forms a cycle? Perhaps a component-oriented algorithm?

Hint 2

We can use the Union-Find (DSU) algorithm to create the graph from the given edges. While connecting the edges, if we fail to connect any edge, it means this is the redundant edge, and we return it. How would you implement this?

Hint 3

Create a DSU (Disjoint Set Union) class and traverse through the given edges. For each edge, attempt to connect the nodes using the union function. If the union function returns false, indicating that the current edge forms a cycle, we immediately return that edge.

Solution

Disjoint Set Union

def find_redundant_connection(edges: list[list[int]]) -> list[int]:
parent = [i for i in range(len(edges) + 1)]
rank = [1] * (len(edges) + 1)
def find(n: int) -> int:
p = parent[n]
while p != parent[p]:
parent[p] = parent[parent[p]]
p = parent[p]
return p
def union(n1: int, n2: int) -> bool:
p1, p2 = find(n1), find(n2)
if p1 == p2:
return False
if rank[p1] > rank[p2]:
parent[p2] = p1
rank[p1] += rank[p2]
else:
parent[p1] = p2
rank[p2] += rank[p1]
return True
for n1, n2 in edges:
if not union(n1, n2):
return [n1, n2]
return []

Time complexity: O(V + (E * A(V))) Space complexity: O(V)