Leetcode|BFS+DFS拓扑排序|210. 课程表 II

2022-01-10 15:17:08 浏览数 (2)

1 BFS拓扑排序

代码语言:javascript复制
class Solution {
public:
    vector<vector<int>> edges;  // 邻接矩阵
    vector<int> indegree;       // 入度表
    vector<int> res;            
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        indegree.resize(numCourses, 0);
        // 1.构造邻接矩阵   入度表
        for (auto edge : prerequisites) {
            edges[edge[1]].push_back(edge[0]);
            indegree[edge[0]]  ;
        }
        // 2.遍历入度表,将入度=0的节点放入队列中,即图的最先驱节点
        queue<int> q;
        for (int i = 0; i < indegree.size(); i  ) 
            if (indegree[i] == 0) q.push(i);
        // 3.从图的最先驱节点一步一步删除,出队,存入res,并遍历每个出队先驱节点的所有子节点,将子节点入度-1,若子节点入度=0,则入队
        while (!q.empty()) {
            int v = q.front(); q.pop();
            res.push_back(v);
            for (auto& subv : edges[v]) {
                indegree[subv]--;
                if (indegree[subv] == 0)
                    q.push(subv);
            }

        }
        // 4.若有环,则res通常比节点数小,比如三个节点成环,则res.size()==0 < 3
        if (res.size() == numCourses) return res;
        return {};
    }
};

2 DFS拓扑排序

代码语言:javascript复制
class Solution {
public:
    vector<vector<int>> edges;  // 邻接矩阵
    vector<int> visited;        // 0-未搜索; 1-已访问; 2-已压栈
    vector<int> res;            // 最终结果
    stack<int> stk;             // 存放结果的栈,图的子节点先入栈,父节点后入栈
    bool vaild = true;          // 是否有环,若有环则直接退出

    void dfs(int v) {
        visited[v] = 1;         // 标记已访问,但不知道子节点是否已访问,故需先DFS访问所有子节点
        for (auto& subv : edges[v]) {   // DFS遍历所有子节点
            if (visited[subv] == 1) {   // 若某个子节点已访问,则存在环,直接退出遍历
                vaild = false;
                return;
            } else if (visited[subv] == 0) {  // 当且仅当子节点为<未搜索>状态时才进行DFS,若visited[subv] == 2则直接跳过即可
                dfs(subv);
                if (!vaild) return;           // 遍历完某个子节点及其孙子节点后发现有环则直接退出遍历
            }
        }
        visited[v] = 2;         // 所有子节点均已访问并压栈,此时标记当前节点为已压栈
        stk.push(v);
    }

    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        visited.resize(numCourses, 0);
        // 1.构建邻接矩阵
        for (auto& edge : prerequisites) 
            edges[edge[1]].push_back(edge[0]);
        // 2.从图中任意选取1个未搜索节点进行DFS (为什么是任意选取?因为只要该节点进行DFS后则对应所有子节点均会压栈,此时其他未搜索节点一定是其先驱节点)
        for (int i = 0; i < numCourses; i  ) {
            if (visited[i] == 0) dfs(i);
            if (!vaild) return {};
        }
        // 3.将stack弹出变成程序需要的vector,若使用vector的reverse(vec.begin(), vec.end())也可节省空间
        while (!stk.empty()) {
            res.emplace_back(stk.top());
            stk.pop();
        }
        return res;
    }
};

0 人点赞