你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 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的一维数组indegrees[]存储顶点的入度
2.创建一个长宽都为numCourses的二维数组adjacency[][]作为图的邻接表
3.创建一个队列q存储入度为0的顶点
4.循环二维数组prerequisites,把其第0列的顶点的入度+1(在indegrees数组对应位置+1),并把其第1列的顶点作为邻接表adjacency对应顶点的第0列。(作为链表结点)
(此处用了for循环的高级形式:
for(vector
5.循环indegrees数组,把入度为0的顶点入队q
6.循环直到队列为空
定义变量pre存储队列的队头元素
队头元素出队
numCourses--(如果是无环有向图,则其所有顶点都应该出队一次,所以numCourses结果应该为0)
循环邻接表,删掉以pre的为弧尾的弧,然后判断是否产生入度为0的顶点,有则入队q
7.如果numCourses为0则返回true,否则返回false
代码:
class Solution {
public:
bool canFinish(int numCourses, vector
vector
vector
(numCourses);
queue
for(vector
indegrees[cp[0]]++;
adjacency[cp[1]].push_back(cp[0]);
}
for(int i=0;i
if(indegrees[i]==0)
q.push(i);
}
while(!q.empty()) {
int pre=q.front();
q.pop();
numCourses--;
for(int cur : adjacency[pre]){
if(--indegrees[cur]==0)
q.push(cur);
}
}
return numCourses==0;
}
};
算法流程:
输入:numCourses = 2, prerequisites = [[1,0]]
indegrees:[1,0](表示顶点0的入度为1,顶点1的入度为0)
adjacency:下标 0 1
0 null null
1 0 null
表示顶点0没有出边,顶点1的出边为顶点0
队列q:[1]
pre=1,1出队,numCourses=1
cur=adjacency[1][0]=0
indegrees[0]=0,0入队q
队列q:[0]
pre=0,0出队,numCourses=0
cur=adjacency[0][0]=null
队列q:[] 为空,退出循环
(numCourses==0)为true
返回true



