1、题目描述
https://leetcode-cn.com/problems/course-schedule/
你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
- 输入的先决条件是由 边缘列表 表示的图形,而不是 邻接矩阵 。
- 你可以假定输入的先决条件中没有重复的边。
- 1 <= numCourses <= 10^5
输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
2、代码详解
入度表(广度优先遍历) 拓扑排序
- 若整个课程安排图是有向无环图(即可以安排),则所有节点一定都入队并出队过,即完成拓扑排序。
- 换个角度说,若课程安排图中存在环,一定有节点的入度始终不为 0。
- 因此,拓扑排序出队次数等于课程个数,返回 numCourses == 0 判断课程是否可以成功安排。
测试用例图如下
numC = 5
prerequisites = [[1, 0], [3, 0], [2, 1], [3, 1], [4, 2], [4, 3]]
s = Solution()
print(s.canFinish(numC, prerequisites))
from typing import List
from collections import deque
class Solution:
# 思想:该方法的每一步总是输出当前无前趋(即入度为零)的顶点
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
"""
numCourses:课程门数,prerequisites:课程与课程之间的关系
"""
# 课程的长度
courselen = len(prerequisites)
if courselen == 0:
# 没有课程,当然可以完成课程的学习
return True
# 步骤1:统计每个顶点的入度
# 入度数组,记录了指向它的结点的个数,一开始全部为 0
in_degrees = [0 for _ in range(numCourses)]
# 邻接表,使用散列表是为了去重
adj = [set() for _ in range(numCourses)]
# 想学习课程 0 ,需要先完成课程 1 ,用一个匹配来表示: [0,1]
# [0, 1] 表示 1 在先,0 在后, 1 -> 0
# 注意:邻接表存放的是后继 successor 结点的集合
for second, first in prerequisites:
in_degrees[second] += 1
adj[first].add(second) # first位置添加其后继second
print("in_degrees", in_degrees)
# 步骤2:拓扑排序开始之前,先把所有入度为 0 的结点加入到一个队列中
# 首先遍历一遍,把所有入度为 0 的结点都加入队列
queue = deque()
for i in range(numCourses):
if in_degrees[i] == 0:
queue.append(i)
counter = 0
while queue:
top = queue.popleft()
counter += 1
# 步骤3:把这个结点的所有后继结点的入度减去 1,如果发现入度为 0 ,就马上添加到队列中
for successor in adj[top]: # 遍历top节点所有的后继
in_degrees[successor] -= 1
if in_degrees[successor] == 0:
queue.append(successor)
return counter == numCourses
时间复杂度:O(E + V)。这里 E 表示邻边的条数,V 表示结点的个数。初始化入度为 0 的集合需要遍历整张图,具体做法是检查每个结点和每条边,因此复杂度为 O(E+V),然后对该集合进行操作,又需要遍历整张图中的每个结点和每条边,复杂度也为 O(E+V);
空间复杂度:O(E + V):邻接表长度是 V,每个课程里又保存了它所有的边。
https://leetcode-cn.com/problems/course-schedule/solution/tuo-bu-pai-xu-by-liweiwei1419/