import collections
from typing import List, Dict, Deque
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
"""
判断是否能完成所有课程的学习(拓扑排序 - Kahn 算法)。
假设 prerequisites 中的 [A, B] 表示 A 是 B 的先修课程 (A -> B)。
Args:
numCourses: 课程总数。
prerequisites: 先修课程要求列表,[[A, B], ...] 表示 A -> B。
Returns:
如果可以完成所有课程,返回 True;否则返回 False。
"""
if numCourses <= 0:
return True
# 1. 初始化入度数组和邻接表
# ingree[i] 存储课程 i 的入度
ingree = [0] * numCourses
# adj[i] 存储以课程 i 为先修课的所有后续课程列表
adj: Dict[int, List[int]] = collections.defaultdict(list)
# 遍历先修课程列表,构建邻接表并计算入度
# 这里根据 C++ 代码的逻辑,将 prerequisites[i][0] 视为先修课 A
# 将 prerequisites[i][1] 视为后续课程 B (A -> B)
for prerequisite in prerequisites:
if len(prerequisite) == 2:
pre = prerequisite[0] # 先修课 A
cur = prerequisite[1] # 当前课 B
adj[pre].append(cur) # 添加 A -> B 的边
ingree[cur] += 1 # B 的入度加 1
else:
# 可以选择忽略无效输入或抛出错误
pass
# 2. 初始化队列,加入所有入度为 0 的课程
queue: Deque[int] = collections.deque()
count = 0 # 记录可以完成的课程数量
for i in range(numCourses):
if ingree[i] == 0:
queue.append(i)
count += 1
# 3. BFS 过程
while queue:
# 取出队首课程(表示完成这门课)
cur_course = queue.popleft()
# 遍历所有以 cur_course 为先修课的后续课程
if cur_course in adj:
for neighbor_course in adj[cur_course]:
# 将后续课程的入度减 1
ingree[neighbor_course] -= 1
# 如果后续课程入度变为 0,则加入队列,并增加计数
if ingree[neighbor_course] == 0:
queue.append(neighbor_course)
count += 1
# 4. 结果判断
# 如果完成的课程数量等于总课程数,说明没有环,可以完成
return count == numCourses
# 示例用法
# solution = Solution()
# numCourses1 = 2
# prerequisites1 = [[1,0]] # 0 -> 1 ? 还是 1 -> 0?
# # 按照代码逻辑 A->B, 这里是 1 -> 0, 0 依赖 1.
# # 初始入度: 0:1, 1:0. 队列: [1]. count=1.
# # Dequeue 1. count=1. 邻居 0. ingree[0] 减为 0. Enqueue 0. count=2. 队列 [0].
# # Dequeue 0. count=2. 无邻居. 队列 [].
# # 返回 count==numCourses (2==2) -> True.
# print(solution.canFinish(numCourses1, prerequisites1)) # 输出: True
# numCourses2 = 2
# prerequisites2 = [[1,0],[0,1]] # 1->0, 0->1 (环)
# # 初始入度: 0:1, 1:1. 队列: []. count=0.
# # 循环不执行.
# # 返回 count==numCourses (0==2) -> False.
# print(solution.canFinish(numCourses2, prerequisites2)) # 输出: False
# numCourses3 = 5
# prerequisites3 = [[0,1],[0,2],[1,3],[1,4],[3,4]] # 0->1, 0->2, 1->3, 1->4, 3->4
# # 初始入度: 0:0, 1:1, 2:1, 3:1, 4:2
# # 队列: [0]. count=1.
# # Dequeue 0. count=1. 邻居 1, 2. ingree[1]=0, ingree[2]=0. Enqueue 1, 2. count=3. 队列 [1, 2].
# # Dequeue 1. count=3. 邻居 3, 4. ingree[3]=0, ingree[4]=1. Enqueue 3. count=4. 队列 [2, 3].
# # Dequeue 2. count=4. 无邻居. 队列 [3].
# # Dequeue 3. count=4. 邻居 4. ingree[4]=0. Enqueue 4. count=5. 队列 [4].
# # Dequeue 4. count=5. 无邻居. 队列 [].
# # 返回 count==numCourses (5==5) -> True.
# print(solution.canFinish(numCourses3, prerequisites3)) # 输出: True
207. 课程表
于 2025-04-11 15:39:58 首次发布