这个题解首先利用了邻接表来表示图的结构。使用并查集来检测边的添加是否会形成环。如果在添加一条边时,该边连接的两个顶点已经在同一个集合中,说明添加这条边会形成一个环。然后,题解利用广度优先搜索(BFS)来寻找最短环。搜索从某个顶点开始,尝试找到通过该点的最短环。如果在过程中发现一个顶点已经访问过(即在当前BFS层次中再次访问),则可以计算形成环的长度。题解中逐个处理每条边,检查其是否形成环,并使用BFS确定环的最短长度。对于每个已经检测过的点,为了减少计算,会从图中断开其连接,避免重复计算。
时间复杂度: O(n^3)
空间复杂度: O(V + E)
class Solution:
def findShortestCycle(self, n: int, edges: List[List[int]]) -> int:
# 构建邻接表
cnt = defaultdict(set)
for i, j in edges:
cnt[i].add(j)
cnt[j].add(i)
# 并查集,用于检测环
dp = list(range(n))
def find(x):
if x != dp[x]:
dp[x] = find(dp[x])
return dp[x]
# 单点出发,检测经过该点的最短伪环
def bfs(i):
dist, res = [0] * n, n + 1
deq = deque([(i, -1)]) # 使用队列实现BFS
while deq and res == n + 1:
cur, pre = deq.popleft()
d = dist[cur] + 1
for j in cnt[cur]:
if j == pre: continue # 避免回头路
if dist[j]: # 如果已访问过j
if dist[j] < d: return dist[j] << 1 | 1
res = d << 1
deq.append((j, cur))
dist[j] = d
return res
meet, res = set(), n + 1
for i, j in edges:
fi, fj = find(i), find(j)
if fi == fj: # 检测到环
if i in meet or j in meet: continue
res = min(res, bfs(i))
meet.add(i)
# 优化:断开已检测点的连接
for k in cnt[i]:
cnt[k].remove(i)
else:
dp[fi] = fj
return res if res != n + 1 else -1