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

LeetCode拓扑排序题代码触发空指针调用错误求助

问题分析与解决

你的运行时错误根源在于在同一个循环迭代中处理多个叶子节点时,会出现对空unordered_set调用begin()并解引用的未定义行为。

举个典型场景:假设节点A和B互相连接,在同一轮循环中先处理A,删除B集合里的A,此时B的集合只剩一个元素;接着处理另一个叶子节点C,删除B集合里的C,此时B的集合变为空。当遍历到B时,graph[B].size() == 0满足<=1的判断条件,这时执行*(graph[B].begin()),但空集合的begin()等于end(),解引用这个迭代器会直接触发空指针类的未定义行为,也就是你看到的报错。

同时,你在同一个for循环里动态修改graph和n,会导致同一轮循环中处理刚被修改状态的节点,逻辑混乱,进一步放大了出错概率。


修复方案

正确的做法是每一轮循环先收集当前所有的叶子节点,再统一处理这些叶子节点的删除操作,避免遍历过程中修改数据导致的迭代问题:

class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
        if (n == 1) return {0};
        vector<unordered_set<int>> graph(n);
        for (auto& edge : edges) {
            graph[edge[0]].insert(edge[1]);
            graph[edge[1]].insert(edge[0]);
        }

        queue<int> leaves;
        // 初始化叶子节点队列
        for (int i = 0; i < n; ++i) {
            if (graph[i].size() == 1) {
                leaves.push(i);
            }
        }

        // 剥洋葱式删除叶子,直到剩余节点数<=2
        while (n > 2) {
            int leafCount = leaves.size();
            n -= leafCount;
            for (int i = 0; i < leafCount; ++i) {
                int leaf = leaves.front();
                leaves.pop();
                int neighbor = *(graph[leaf].begin());
                graph[neighbor].erase(leaf);
                // 如果邻居变成新的叶子,加入队列
                if (graph[neighbor].size() == 1) {
                    leaves.push(neighbor);
                }
            }
        }

        // 收集剩余的根节点
        vector<int> res;
        while (!leaves.empty()) {
            res.push_back(leaves.front());
            leaves.pop();
        }
        return res;
    }
};

关键修复点
  • 用队列收集每一轮的叶子节点,统一处理,避免遍历过程中修改数据引发的迭代错误
  • 仅当节点的邻居集合大小为1时才视为叶子,避免处理空集合的情况
  • 每一轮处理固定数量的叶子节点(当前队列的大小),保证n的递减逻辑准确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 20:05:31