从LeetCode 210. Course Schedule II 了解拓扑排序

问题简述

给定n节课,每节课按0~n-1编号。
在修某些课的时候需要有其它课的基础,必须先上先修课。现在用pair的形式来表示要先修的课,比如 [ [0,1], [1,2] ] 就表示在修课程1之前必须先修课程0,修课程2之前必须修课程1。现在需要给出一个修课的顺序,使得按照该顺序修课可以顺利得到所有学分。
现在的输入为课程数和先修的顺序,输出为修课顺序中的一种。
比如:

例子1
输入:
2, [[1,0]]
表示共有两门课,在修课程1之前必须修课程0
输出:
[0, 1]
表示修课顺序为0->1

又比如:

例子2
输入:
4, [[1,0],[2,0],[3,1],[3,2]]
输出:
[0,1,2,3] 或者 [0,2,1,3](其中一个即可)

再比如:

例子3
输入:
2, [[1,0], [0,1]]
输出:
[]
因为无法满足修课程1之前修课程0,同时修课程0之前修课程1,所以返回空

解决思路

其实这个问题就是让我们在给定的输入下,判断能否完成拓扑排序。何为拓扑排序(详见这里)?
比如,在输入为

4, [[1,0],[2,0],[3,1],[3,2]]

的情况下,得到的下图1就是一个拓扑排序,也就是一个没有环的有向图。
拓扑排序

图1 拓扑排序示意图
比如改变一下输入 ``` 4, [[1,0],[2,0],[3,1],[3,2],[0,3]] ``` 得到了一个有环图,那么这就不是一个排序了

非拓扑排序

图2 非拓扑排序示意图
很简单吧~接下来只判断给定的输入能否构成拓扑排序,可以的话输出拓扑序列,不可以的话输出空即可。 那么,如何判断呢?这就可以根据入度(indegree)来判断了。所谓入度,就是构成有向图之后,指向各个节点的边数。 具体步骤是,我们每次去掉入度为0的点,将该点加入拓扑排序,同时删去与其连接的边(其它节点的入度会受到影响),直到去掉所有的点为止,如果中途遇到不存在入度为0的点的情况,那么,就认为这个有向图不是拓扑排序的。 比如图1可以如下操作

拓扑排序状态

图3 拓扑排序状态图
而图2中则直接找不到入度为0的点,认为是非拓扑排序。

源代码

下面是一个基于BFS的拓扑排序思路,其实也不能说是严格意义上的BFS,只是有点像~

struct Node{
    int indegree;
    vector<int> adjacency;
    Node(){
        indegree = 0;
        adjacency.clear();
    }
};

class Solution {
private:
    vector<int> res;
    
public:
    vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<Node*> vec;
        for (int i = 0; i < numCourses; i++){
            vec.push_back(new Node());
        }
        for (int i = 0; i < prerequisites.size(); i++){
            vec[prerequisites[i].first]->indegree++;
            vec[prerequisites[i].second]->adjacency.push_back(prerequisites[i].first);
        }
        for (int i = 0; i < vec.size(); i++){
            int j = 0;
            for (; j < vec.size(); j++){
                if (vec[j]->indegree == 0){
                    res.push_back(j);
                    vec[j]->indegree = -1;
                    for (int item : vec[j]->adjacency){
                        vec[item]->indegree--;
                    }
                    break;
                }
            }
            if (j == vec.size()){
                res.clear();
                return res;
            }
        }
        return res;
    }
};
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七元权

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值