You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

拓扑排序验证无向图为有效树的问题排查

判断无向图是否为有效树的拓扑排序解法问题

问题背景

给定一个包含n个节点(标签0到n-1)的无向图,已知整数n和边列表edges,其中edges[i] = [ai, bi]表示节点ai和bi之间存在一条无向边。需要判断该图的边是否构成一棵有效树,是则返回true,否则返回false。

遇到的问题

我尝试用拓扑排序算法判断图中是否存在环,但在某个测试用例中,明明图存在环,却输出了完整的拓扑排序序列,导致错误返回true。

我的代码

class Solution:
    def validTree(self, n: int, edges: List[List[int]]) -> bool:
        indegree = [0]*(n)
        
        graph = {i:[] for i in range(n)}
        
        for child,parent in edges:
            indegree[child]+=1
            graph[parent].append(child)
            
        
        q = deque([])
        
        for i in range(len(indegree)):
            if indegree[i] == 0:
                q.append(i)
                
        top_order = []

        while q:
            node = q.popleft()
            top_order.append(node)
            for child in graph[node]:
                indegree[child]-=1
                if indegree[child]==0:
                    q.append(child)
        print(top_order)    
        return len(top_order)==n

测试用例情况

  • 输入:n = 5,edges = [[0,1],[0,2],[0,3],[1,4],[1,3]]
  • 运行结果:top_order = [2, 3, 4, 1, 0],返回true,但预期应为false(图中0-1-3-0构成环)

问题原因

拓扑排序是针对有向图的算法,你处理无向图时的邻接表和入度统计完全错误:

  • 无向边[a,b]等价于双向有向边a→b和b→a,但你只把每条边当成单向的child→parent,导致入度统计严重偏差。比如测试用例中的边[0,3],你只给3的入度加1,却没给0的入度加1,环中的节点入度没有被正确统计,最终拓扑排序能遍历所有节点,误判无环。

正确解决方案

判断无向图是否为有效树,必须同时满足两个条件:无环且所有节点连通(树的边数固定为n-1,先通过这个条件快速过滤不符合的情况)。

方法一:适配无向图的BFS(类拓扑排序思路)

把无向边当成双向边处理,用父节点记录避免走回头路,同时判断环和连通性:

from collections import deque
from typing import List

class Solution:
    def validTree(self, n: int, edges: List[List[int]]) -> bool:
        # 树的边数必须是n-1,直接过滤不符合的情况
        if len(edges) != n - 1:
            return False
        
        # 构建无向邻接表
        graph = [[] for _ in range(n)]
        for a, b in edges:
            graph[a].append(b)
            graph[b].append(a)
        
        visited = [False] * n
        q = deque([0])
        visited[0] = True
        parent = [-1] * n  # 记录父节点,防止回走
        
        while q:
            node = q.popleft()
            for neighbor in graph[node]:
                if not visited[neighbor]:
                    visited[neighbor] = True
                    parent[neighbor] = node
                    q.append(neighbor)
                elif parent[node] != neighbor:
                    # 遇到已访问节点且不是父节点,说明存在环
                    return False
        
        # 检查所有节点是否都被访问(确保连通)
        return all(visited)

方法二:并查集(Union-Find)

并查集是判断无向图环和连通性的高效方法:

from typing import List

class Solution:
    def validTree(self, n: int, edges: List[List[int]]) -> bool:
        if len(edges) != n - 1:
            return False
        
        parent = list(range(n))
        
        def find(x):
            # 路径压缩
            if parent[x] != x:
                parent[x] = find(parent[x])
            return parent[x]
        
        def union(x, y):
            fx, fy = find(x), find(y)
            if fx == fy:
                return False  # 两个节点已连通,存在环
            parent[fy] = fx
            return True
        
        for a, b in edges:
            if not union(a, b):
                return False
        
        return True

内容的提问来源于stack exchange,提问作者ndnchapathi69

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 06:47:40