Given an undirected graph with V vertices (0 .. V-1) and an edge list edges (no self-loops or duplicate edges), return true if it contains a cycle and false otherwise.
Input: V = 3, edges = [[0,1],[1,2],[2,0]] Output: true The three edges form a triangle.
Input: V = 4, edges = [[0,1],[1,2],[2,3]] Output: false A path has no cycle.
- 1 <= V <= 10^5 - 0 <= edges.length <= 10^5 - no self-loops or duplicate edges
In an undirected graph, a cycle shows up as an edge that reconnects two already-connected vertices. Two clean detectors:
Traversal with parent tracking. BFS/DFS each component; a cycle exists if you reach an already-visited vertex that isn't the parent you came from. The parent check is crucial — the edge back to your immediate parent is not a cycle, just the edge you arrived on.
Union-Find. Process edges; for each (u, v), if u and v are already in the same set, this edge forms a cycle. Otherwise union them. A single pass over the edges, near-O(E·α).
“Could the graph be disconnected?”
Yes — check every component.
“Self-loops or parallel edges?”
Assumed absent here; both would count as cycles if present.
I BFS each component tracking the parent; reaching a visited non-parent vertex means a cycle.
Or union-find: an edge whose endpoints already share a set closes a cycle.
Worked example — V = 3, edges [[0,1],[1,2],[2,0]]
union 0-1, union 1-2, then edge 2-0: 2 and 0 already connected -> cycle
Beyond a spanning tree's V-1 edges per component, any edge closes a cycle.
Reaching the parent isn't a cycle; reaching any other visited vertex is.
A cycle can hide in any disconnected piece.
| BFS + parent | Union-Find | |
|---|---|---|
| Signal | visited non-parent neighbour | edge within one set |
| Time | O(V+E) | O(E·α) |
| Best when | graph given up front | edges stream in |
Both detect the same cycles. Full code is in the Approaches selector below.
Key takeaway
A cycle is a redundant edge. Traverse tracking parents (visited non-parent ⇒ cycle), or union edges (same-set endpoints ⇒ cycle). Near-linear.
bfs: if neighbour visited and != parent -> cycle dsu: if find(u) == find(v) -> cycle else union