↓快轉到主要內容
  1. LeetCode/

LeetCode 2608: Shortest Cycle in a Graph

·2 分鐘· ·
LeetCode Hard Bfs Graph
Wei Yi Chung
作者
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
目錄

基本資料
#

難易度: hard 第一次嘗試:2026-09-16

  • 提交紀錄:Wrong Answer → Memory Limit Exceeded → Accepted

解題思路
#

無向圖的最短環。n, m <= 1000,所以可以從每個點各做一次 BFS。

從 s 做 BFS 時,記錄每個點的距離 dist 和它從哪裡來(parent)。如果從 u 看到一個已經拜訪過、而且不是 u 的 parent 的鄰居 v,代表有兩條從 s 出發的路徑在 u-v 這條邊相遇,形成一個環,長度最多是 dist[u] + dist[v] + 1。

這個長度不一定剛好是環的長度(兩條路徑可能在離 s 比較近的地方就會合了),但會是某個環的長度上界;而對最短環上的任一點做 BFS 時,一定能算出它的正確長度。所以所有起點、所有這種邊取最小值,就是答案。

我的嘗試
#

Wrong Answer:用「走過的邊」當狀態
#

第一版的 BFS 狀態是 (長度, 目前節點, 走過的邊的位元遮罩),想直接找「回到同一個點、但沒有重複用邊」的路徑。除了思路太重,位元檢查也寫錯了:

if not (visited_edge >> edge):            # 應該是 (visited_edge >> edge) & 1

visited_edge >> edge 只要比 edge 更高的位元有任何一個是 1 就是 True,不是只看第 edge 位。

Memory Limit Exceeded:狀態數爆炸
#

修好位元檢查之後,每條路徑都帶著自己的邊遮罩,同一個節點會以非常多種不同的遮罩被推進 queue,記憶體爆掉。

最後改成標準做法:每個點 BFS 一次,只記距離和 parent。

正確解法
#

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

複雜度
#

時間 O(n · (n + m)),空間 O(n + m)。

要特別避免的錯誤
#

  • 用走過的邊集合當狀態:狀態數是指數級。
  • 位元檢查少了 & 1。
  • 把 parent 也當成環:無向圖每條邊都會被雙向看到,要排除剛走過來的那條邊。

面試口說整理
#

我從每個點各做一次 BFS,記錄距離和 parent。遇到一個已經拜訪過、而且不是 parent 的鄰居,就代表兩條路徑在這條邊相遇,形成長度 dist[u] + dist[v] + 1 的環。對最短環上的點做 BFS 時一定能得到它的正確長度,所以全部取最小值就是答案。總共 n 次 BFS,時間 O(n(n + m))。

相關文章

LeetCode 1377: Frog Position After T Seconds
·2 分鐘
LeetCode Hard Tree Dfs Bfs Graph Probability
LeetCode 1377 解題筆記:無向邊、seen 要記節點、提早到達目標時要看還能不能走
LeetCode 1210: Minimum Moves to Reach Target with Rotations
·2 分鐘
LeetCode Hard Bfs Matrix
LeetCode 1210 解題筆記:BFS 的狀態是 (蛇尾位置, 方向),四種移動各自檢查需要空的格子;每步成本相同不需要 heap
LeetCode 4046: Minimum Cost Path With At Most K Turns
·2 分鐘
LeetCode Hard Graph Shortest-Path Heap Matrix
LeetCode 4046 解題筆記:Dijkstra 的狀態加上「上一步方向」和「已轉彎數」;同一格同方向時,先處理的成本較低,轉彎數也較少的話就支配後面的狀態
LeetCode 2603: Collect Coins in a Tree
·2 分鐘
LeetCode Hard Tree Graph Topological-Sort
LeetCode 2603 解題筆記:先剪掉沒有硬幣的葉子,再固定剪兩層,剩下的邊走兩次
LeetCode 1782: Count Pairs Of Nodes
·2 分鐘
LeetCode Hard Two-Pointers Graph Sorting Hash-Table Counting
LeetCode 1782 解題筆記:先用排序後的度數 + 對撞指針數 deg[a] + deg[b] > q 的配對,再對有共用邊的配對修正多算的部分
LeetCode 499: The Maze III
·2 分鐘
LeetCode Hard Graph Dijkstra Shortest-Path Heap Matrix
LeetCode 499 解題筆記:Dijkstra 的優先度用 (距離, 路徑字串),滾動途中經過洞就要停下