课程表-leetcode
题目描述
你这个学期必须选修 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 <= 20000 <= prerequisites.length <= 5000prerequisites[i].length == 20 <= ai, bi < numCoursesprerequisites[i]中的所有课程对 互不相同
解法一
思路:
拓扑排序的原理是:如果一个有向图是无环的(DAG),那么它一定存在一个入度为 0 的顶点。我们可以不断移除入度为 0 的顶点,如果最后所有顶点都被移除了,说明没有环。
算法步骤:
- 统计入度:遍历邻接矩阵,统计每个顶点的入度(即每一列中 1 的个数)。
- 寻找起点:将所有入度为 0 的顶点放入一个队列中。
- 循环处理:
- 从队列中取出一个顶点 u。
- 遍历该顶点 u 的所有出边(邻接矩阵中第 uu行值为 1 的列 v)。
- 将顶点 v 的入度减 1。
- 如果 v 的入度变为 0,则将 v 放入队列。
- 判断结果:记录从队列中取出的顶点总数。如果总数等于图中顶点的总数,则没有环;否则,有环。
代码:
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int[][] graph = new int[numCourses][numCourses];
//统计节点的入度
int[] indegree = new int[numCourses];
//出队的节点数
int num=0;
//构建图
for(int i=0;i<prerequisites.length;i++){
graph[prerequisites[i][1]][prerequisites[i][0]] = 1;
indegree[prerequisites[i][0]]++;
}
//入度为0的节点进入队列
Queue<Integer> queue = new LinkedList<>();
for(int i=0;i<numCourses;i++){
if(indegree[i]==0){
queue.offer(i);
}
}
//拓扑排序
while(!queue.isEmpty()){
int cur = queue.poll();
num++;
for(int j=0;j<numCourses;j++){
if(graph[cur][j]==1){
indegree[j]--;
if(indegree[j]==0){
queue.offer(j);
}
}
}
}
return num==numCourses;
}
}

浙公网安备 33010602011771号