In this problem, a tree is an undirected graph that is connected and has no cycles.
You are given a graph that started as a tree with n nodes labeled from 1 to n, with one additional edge added. The added edge has two different vertices chosen from 1 to n, and was not an edge that already existed. The graph is represented as an array edges of length n where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the graph.
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.
Example 1:
Input: edges = [[1,2],[1,3],[2,3]] Output: [2,3]
Example 2:
Input: edges = [[1,2],[2,3],[3,4],[1,4],[1,5]] Output: [1,4]
Constraints:
n == edges.length3 <= n <= 1000edges[i].length == 21 <= ai < bi <= edges.lengthai != biThe key idea in #684 Redundant Connection is to detect the edge that creates a cycle in an undirected graph. Since the graph initially forms a tree and then receives one extra edge, that additional edge will connect two nodes that are already indirectly connected.
A common and efficient strategy is using the Union-Find (Disjoint Set Union) data structure. As you iterate through each edge, check whether the two nodes already belong to the same set using find(). If they do, adding this edge would form a cycle, making it the redundant connection. Otherwise, merge their sets using union().
An alternative approach uses DFS or BFS. Before adding an edge, perform a traversal to see if a path already exists between the two nodes. If a path exists, the current edge creates a cycle.
The Union-Find method is generally preferred because it processes edges efficiently with near-constant time operations, making it well suited for graph connectivity problems.
| Approach | Time Complexity | Space Complexity |
|---|---|---|
| Union-Find (Disjoint Set) | O(n α(n)) | O(n) |
| DFS / BFS Cycle Check | O(n^2) in worst case | O(n) |
NeetCode
This approach utilizes the Union-Find (or Disjoint Set Union, DSU) data structure to detect cycles. The key operations in Union-Find are 'find', which determines the representative of a set, and 'union', which merges two sets. When processing each edge, we attempt to unite the vertices. If both vertices are already in the same set, a cycle is detected, and this edge is the redundant one.
Time Complexity: O(n) where n is the number of edges because we process each edge once.
Space Complexity: O(n) due to the storage of the parent and rank arrays.
1#include <stdio.h>
2#include <stdlib.h>
3
4typedef struct {
5 int *root;
6 int *
This C solution applies a similar Union-Find algorithm. It allocates memory for the root and rank arrays and implements the same logic through find and unionSets functions, efficiently detecting the redundant edge via a cycle.
The DFS approach involves simulating the construction of the graph and utilizing DFS to detect cycles whenever a new edge is being added. If a cycle is detected upon adjacent traversal, that edge is the redundant one.
Time Complexity: O(n^2), potentially examining each pair of nodes connected by added edges in the worst case.
Space Complexity: O(n), dictated by recursive stack depth in the DFS and the graph representation.
1#include <unordered_set>
#include <unordered_map>
using namespace std;
bool dfs(int source, int target, unordered_map<int, unordered_set<int>>& graph, unordered_set<int>& visited) {
if (source == target) return true;
visited.insert(source);
for (int neighbor : graph[source]) {
if (!visited.count(neighbor)) {
if (dfs(neighbor, target, graph, visited)) return true;
}
}
return false;
}
class Solution {
public:
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
unordered_map<int, unordered_set<int>> graph;
for (auto& edge : edges) {
int u = edge[0], v = edge[1];
unordered_set<int> visited;
if (graph.count(u) && graph.count(v) && dfs(u, v, graph, visited)) {
return edge;
}
graph[u].insert(v);
graph[v].insert(u);
}
return {};
}
};Watch expert explanations and walkthroughs
Practice problems asked by these companies to ace your technical interviews.
Explore More ProblemsJot down your thoughts, approach, and key learnings
Yes, graph connectivity and Union-Find problems like Redundant Connection are commonly discussed in technical interviews at top companies. They test understanding of cycles, graph traversal, and efficient data structure design.
Yes, you can use DFS or BFS to check if a path already exists between two nodes before adding an edge. If a path exists, the edge would create a cycle, making it redundant. However, this approach is usually less efficient than Union-Find.
The optimal approach uses the Union-Find (Disjoint Set Union) data structure. It helps track connected components efficiently and detects when an edge connects two nodes already in the same set, indicating a cycle.
Union-Find is the most suitable data structure for this problem because it efficiently manages connectivity and cycle detection in graphs. It supports near constant-time union and find operations with path compression and rank optimization.
In this C++ solution, a graph is represented via adjacency lists, utilizing sets to store edges and detect cycles using DFS. Upon discovery of a concurrent cycle path between nodes, the processing edge is flagged as redundant.