↓Skip to main content
  1. LeetCode/

LeetCode 2608: Shortest Cycle in a Graph

·3 mins· ·
LeetCode Hard Bfs Graph
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: hard First Attempt: 2026-09-16

  • Submissions: Wrong Answer → Memory Limit Exceeded → Accepted

Approach
#

Find the shortest cycle in an undirected graph. With n, m <= 1000, one BFS from every node is affordable.

During a BFS from s, record each node’s distance dist and where it came from (its parent). If, from u, you see a neighbor v that is already visited and is not u’s parent, two paths from s meet across the edge u-v and form a cycle of length at most dist[u] + dist[v] + 1.

That length is not always exactly a cycle’s length (the two paths may merge before reaching s), but it is an upper bound on some cycle, and a BFS started on the shortest cycle itself computes its exact length. So the minimum over all starts and all such edges is the answer.

My Attempts
#

Wrong Answer: traversed edges as state
#

The first BFS state was (length, current node, bitmask of traversed edges), trying to find paths that return to a node without reusing an edge. Besides being far too heavy, the bit test was wrong:

if not (visited_edge >> edge):            # should be (visited_edge >> edge) & 1

visited_edge >> edge is truthy whenever any bit higher than edge is set, not only bit edge.

Memory Limit Exceeded: the state space exploded
#

With the bit test fixed, every path carried its own edge mask, so the same node was pushed with a huge number of different masks and memory ran out.

The final version used the standard approach: one BFS per node, tracking only distance and parent.

Solution
#

from collections import defaultdict, deque

class Solution:
    def findShortestCycle(self, n: int, edges: List[List[int]]) -> int:
        adj = defaultdict(list)
        for u, v in edges:
            adj[u].append(v)
            adj[v].append(u)

        best = float("inf")
        for s in range(n):
            dist = [-1] * n
            dist[s] = 0
            q = deque([(s, -1)])
            while q:
                u, parent = q.popleft()
                for v in adj[u]:
                    if dist[v] == -1:
                        dist[v] = dist[u] + 1
                        q.append((v, u))
                    elif v != parent:
                        best = min(best, dist[u] + dist[v] + 1)
        return -1 if best == float("inf") else best

Complexity
#

Time O(n · (n + m)), space O(n + m).

Mistakes to Avoid
#

  • Using the set of traversed edges as state: the number of states is exponential.
  • Testing a bit without & 1.
  • Counting the parent as a cycle: in an undirected graph every edge is seen from both ends, so exclude the edge just used.

Interview Explanation
#

I run one BFS from every node, tracking distance and parent. A visited neighbor that is not the parent means two paths meet across that edge, forming a cycle of length dist[u] + dist[v] + 1. A BFS started on the shortest cycle gets its exact length, so the minimum over everything is the answer. That is n BFS runs, O(n(n + m)) time.

Related

LeetCode 1377: Frog Position After T Seconds
·3 mins
LeetCode Hard Tree Dfs Bfs Graph Probability
LeetCode 1377 note: undirected edges, seen must hold nodes, and an early arrival depends on whether the frog can still move
LeetCode 1210: Minimum Moves to Reach Target with Rotations
·3 mins
LeetCode Hard Bfs Matrix
LeetCode 1210 note: the BFS state is (tail position, orientation), each move checks its own empty cells, and equal step costs need no heap
LeetCode 4046: Minimum Cost Path With At Most K Turns
·3 mins
LeetCode Hard Graph Shortest-Path Heap Matrix
LeetCode 4046 note: Dijkstra with the last direction and the turns used in the state; for the same cell and direction, an earlier pop is cheaper, and if it also used fewer turns it dominates later states
LeetCode 2603: Collect Coins in a Tree
·4 mins
LeetCode Hard Tree Graph Topological-Sort
LeetCode 2603 note: trim coin-free leaves, trim exactly two more layers, and walk each remaining edge twice
LeetCode 1782: Count Pairs Of Nodes
·3 mins
LeetCode Hard Two-Pointers Graph Sorting Hash-Table Counting
LeetCode 1782 note: count pairs with deg[a] + deg[b] > q using sorted degrees and converging pointers, then correct the over-count for pairs that share edges
LeetCode 499: The Maze III
·3 mins
LeetCode Hard Graph Dijkstra Shortest-Path Heap Matrix
LeetCode 499 note: Dijkstra prioritized by (distance, path string), and the ball stops when it rolls over the hole