207. 课程表
难度⭐⭐
你这个学期必须选修 numCourse
门课程,记为 0
到 numCourse-1
。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
示例 1:
输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
分析
根据题意可以将课程之间的关系以有向图的方式存储,节点之间的连接表示关系,边的权重可以用先修课程数表示(记为节点的入度)
- 遍历求出每个节点的入度(先修数),并存储图
- 由于入度数表示先修数,入度为0的课程可以修
- 将入度为0节点入队列(BFS),每有一个邻接节点就将入度减一
- 判断可修课程数是否等于总课数
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
from collections import defaultdict
graph = defaultdict(list)
indeg = [0]*numCourses
#存储图以及入度
for rel in prerequisites:
indeg[rel[0]] += 1
graph[rel[1]].append(rel[0])
#BFS 入度0节点入队列
res = []
q = [cou for cou,deg in enumerate(indeg) if deg == 0]
while q:
node = q.pop(0)
res.append(node)
for i in graph[node]:#判断邻接节点入度是否为0(可以入队列)
indeg[i] -= 1
if indeg[i] == 0:
q.append(i)
return True if len(res) == numCourses else False
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
//定义邻接矩阵和存储入度的数组
List<List<Integer>> graph = new ArrayList<List<Integer>>();
for (int i = 0; i < numCourses; ++i) {
graph.add(new ArrayList<Integer>());
}
int[] indeg = new int[numCourses];
for(int[] info : prerequisites){
indeg[info[0]] += 1;
graph.get(info[1]).add(info[0]);
}
//BFS 创建队列 入度为0入队
Queue<Integer> q = new LinkedList<Integer>();
for(int i=0; i<numCourses; i++){
if(indeg[i] == 0) q.offer(i);
}
while(!q.isEmpty()){
int node = q.poll();
numCourses--;
for (int v: graph.get(node)) {
--indeg[v];
if (indeg[v] == 0) {
q.offer(v);
}
}
}
return numCourses == 0;
}
}