LeetCode 207. 课程表 【c++/java详细题解】

324 阅读3分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战

1、题目

你这个学期必须选修 numCourses门课程,记为 0numCourses - 1

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false

示例 1:

 输入:numCourses = 2, prerequisites = [[1,0]]
 输出:true
 解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。

示例 2:

 输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
 输出:false
 解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。

提示:

  • 1 <= numCourses <= 105
  • 0 <= prerequisites.length <= 5000
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • prerequisites[i] 中的所有课程对 互不相同

2、思路

拓扑排序: O(n+m)O(n+m)

对一个有向无环图G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点uv,若<u,v> ∈E(G),则u在线性序列中出现在v之前。

image-20211118203550909.png

一个合法的选课序列就是一个拓扑序,拓扑序是指一个满足有向图上,不存在一条边出节点在入节点前的线性序列,如果有向图中有环,就不存在拓扑序。可以通过拓扑排序算法来得到拓扑序,以及判断是否存在环。

拓扑排序步骤:

  • 1、建图并记录所有节点的入度。
  • 2、将所有入度为0的节点加入队列。
  • 3、取出队首的元素now,将其加入拓扑序列。
  • 4、访问所有now的邻接点nxt,将nxt的入度减1,当减到0后,将nxt加入队列。
  • 5、重复步骤34,直到队列为空。
  • 6、如果拓扑序列个数等于节点数,代表该有向图无环,且存在拓扑序。

时间复杂度分析: 假设 n 为点数,m 为边数,拓扑排序仅遍历所有的点和边一次,故总时间复杂度为 O(n+m)。

3、c++代码

 class Solution {
 public:
     /**
      1、建图并记录所有节点的入度。
      2、将所有入度0的节点加入队列。
      3、取出队首的元素now,将其加入拓扑序列。
      4、访问所有now的邻接点nxt,将nxt的入度减1,当减到0后,将nxt加入队列。
      5、重复步骤3、4,直到队列为空。 
      6、如果拓扑序列个数等于节点数,代表该有向图无环,且存在拓扑序。
     **/
     bool canFinish(int n, vector<vector<int>>& edges) {
         vector<vector<int>> g(n);
         vector<int> d(n);  // 存贮每个节点的入度
         for(auto edge : edges){
             g[edge[1]].push_back(edge[0]);  //建图
             d[edge[0]]++;  //入度加1
         }
 ​
         queue<int> q;
         for(int i = 0; i < n; i++){
             if(d[i] == 0) q.push(i);  //将所有入度为0的节点加入队列。
         }
 ​
         int cnt = 0;  //统计拓扑节点的个数
         while(q.size()){
             int t = q.front();
             q.pop();
             cnt++;
             for(int i : g[t]){  //访问t的邻接节点
                 d[i]--;
                 if(d[i] == 0) q.push(i);
             }
         }
         
         return cnt == n;
     }
 };