• 207. 课程表


    Tag

    拓扑排序】【2023-09-09】


    题目来源

    207. 课程表


    题目解读

    在选修某些课程之前需要先学习某些课程,先学习的课程有数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] 表示为学习课程 ai 之前要先学习课程 bi。请你判断是否可以完成 numCourses 课程数的课程。


    解题思路

    方法一:拓扑排序

    这是一道典型的拓扑排序问题。在学习某些课程之前需要先选修学习一些其他的课程,有先后顺序的限制,因此可以使用拓扑排序来解题。拓扑排序方法的基本步骤如下:

    • 计算每个节点的入度;
    • 将入度为 0 的节点加入到队列 que 中;
    • 依次枚举 que 中的节点 node,将与 node 相连的节点 node2 的入度 -1,如果节点 node2 的入度为 0,则将其加入到队列 que 中;

    在枚举队列中的节点时,对节点进行标记或者一些特殊处理从而解决相应的问题。在本题中,在枚举队列中的节点时,维护一个变量 cnts 对节点进行计数,如果枚举结束后 cnts != numCourses 则表明选修限制中存在环,即互为先决条件的情况。

    在具体实现中,需要定义一个二维数组来建立课程之间的边,还需要一个一维数组 in 来记录各个课程的入度。首先,遍历课程关系数组 prerequisties 更新课程的度以及课程之间的边关系;接着,将度为 0 的课程编号存入队列 q 中;然后,依次枚举队列中的课程,并更新与当前枚举的课程连接的新的课程的入度 -1,如果更新后新的课程入度为 0,则将入队列中,并且在枚举队列中课程时,将计数变量 visited +1;最后,如果计算变量与课程数量有如下关系:visted = numCourses,则表明可以完成所有课程的学习,否则不能。

    实现代码

    class Solution {
        vector<vector<int>> edges;      // 课程之间的边
        vector<int> in;                 // 课程的入度
    public:
        bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
            edges.resize(numCourses);
            in.resize(numCourses);
            for(auto prerequisite : prerequisites){
                edges[prerequisite[1]].push_back(prerequisite[0]);
                ++ in[prerequisite[0]];
            }
    
            queue<int> q;
            for(int i = 0; i < in.size(); ++i){
                if(in[i] == 0){
                    q.push(i);
                }
            }
    
            int visited = 0;
            while(!q.empty()){
                int u =q.front();
                q.pop();
                ++ visited;
    
                for(int i = 0; i < edges[u].size(); ++i){
                    -- in[edges[u][i]];
                    if(in[edges[u][i]] == 0){
                        q.push(edges[u][i]);
                    }
                }
            }
            
            return visited == numCourses;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    复杂度分析

    时间复杂度: O ( n + m ) O(n+m) O(n+m),其中 n n n 为课程数, m m m 选修课程限制数组的长度。

    空间复杂度: O ( n + m ) O(n+m) O(n+m),课程之间建立邻接表的空间复杂度为 O ( n + m ) O(n+m) O(n+m)。广搜中使用最多 O ( n ) O(n) O(n) 的队列空间。因此总空间复杂度为 O ( n + m ) O(n+m) O(n+m)

    知识回顾

    拓扑排序的含义与应用可参考 广度优先搜索(5)之拓扑排序

    写在最后

    如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

    如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

    最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

  • 相关阅读:
    排序算法——希尔排序
    代理IP与Socks5代理:跨界电商智能爬虫的引擎与安全壁垒
    基于FPGA的视频接口之千兆网口(一)
    SpringBoot结合Liquibase实现数据库变更管理
    母婴类目电商平台数据分析
    嵌入式linux实现pppoe拨号上网
    java: PushbackInputStream
    不小心误删的文件怎么恢复?三个方法解决烦恼
    顺丰面试,第二个问题把我劝退了!
    什么是微服务?与分布式又有什么区别?
  • 原文地址:https://blog.csdn.net/weixin_54383080/article/details/132783339