Skip to content

Commit fc075a6

Browse files
committed
Course schedule
1 parent 939acd8 commit fc075a6

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

207.course_schedule/schedule.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# 207. Course schedule
2+
# Topics: 'Depth-First Search', 'Breadth-first Search', 'Graph'
3+
# Level: 'Medium'
4+
5+
# There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you must take course bi first if you want to take course ai.
6+
7+
# For example, the pair [0, 1], indicates that to take course 0 you have to first take course 1.
8+
9+
# Return true if you can finish all courses. Otherwise, return false.
10+
11+
12+
13+
# Example 1:
14+
15+
# Input: numCourses = 2, prerequisites = [[1,0]]
16+
# Output: true
17+
# Explanation: There are a total of 2 courses to take.
18+
# To take course 1 you should have finished course 0. So it is possible.
19+
20+
# Example 2:
21+
22+
# Input: numCourses = 2, prerequisites = [[1,0],[0,1]]
23+
# Output: false
24+
# Explanation: There are a total of 2 courses to take.
25+
# To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.
26+
27+
28+
29+
# Constraints:
30+
31+
# 1 <= numCourses <= 2000
32+
# 0 <= prerequisites.length <= 5000
33+
# prerequisites[i].length == 2
34+
# 0 <= ai, bi < numCourses
35+
# All the pairs prerequisites[i] are unique.
36+
37+
from collections import deque
38+
from typing import List
39+
40+
class Solution:
41+
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
42+
adjlist = {i: [] for i in range(numCourses)}
43+
for a, b in prerequisites:
44+
adjlist[a].append(b)
45+
46+
def has_cycle(node: int)->bool:
47+
if node in visit:
48+
# cycle detected
49+
return True
50+
if adjlist[node] == []:
51+
return False
52+
visit.add(node)
53+
for n in adjlist[node]:
54+
if has_cycle(n):
55+
return True
56+
visit.remove(node)
57+
adjlist[node] = []
58+
return False
59+
60+
visit = set()
61+
for c in range(numCourses):
62+
if has_cycle(c):
63+
# cannot complete all courses
64+
return False
65+
return True
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
from typing import List
2+
from collections import deque
3+
from schedule import Solution
4+
5+
def test_course_schedule():
6+
solution = Solution()
7+
8+
# Test 1: Example 1 - Simple valid case
9+
assert solution.canFinish(2, [[1, 0]]) == True, "Test 1 failed"
10+
print("✓ Test 1 passed: Simple valid case")
11+
12+
# Test 2: Example 2 - Simple cycle
13+
assert solution.canFinish(2, [[1, 0], [0, 1]]) == False, "Test 2 failed"
14+
print("✓ Test 2 passed: Simple cycle")
15+
16+
# Test 3: No prerequisites
17+
assert solution.canFinish(3, []) == True, "Test 3 failed"
18+
print("✓ Test 3 passed: No prerequisites")
19+
20+
# Test 4: Single course
21+
assert solution.canFinish(1, []) == True, "Test 4 failed"
22+
print("✓ Test 4 passed: Single course")
23+
24+
# Test 5: Linear dependency chain
25+
assert solution.canFinish(4, [[1, 0], [2, 1], [3, 2]]) == True, "Test 5 failed"
26+
print("✓ Test 5 passed: Linear dependency chain")
27+
28+
# Test 6: Complex valid dependencies
29+
assert solution.canFinish(5, [[1, 0], [2, 0], [3, 1], [3, 2], [4, 3]]) == True, "Test 6 failed"
30+
print("✓ Test 6 passed: Complex valid dependencies")
31+
32+
# Test 7: Cycle in middle of chain
33+
assert solution.canFinish(3, [[0, 1], [1, 2], [2, 1]]) == False, "Test 7 failed"
34+
print("✓ Test 7 passed: Cycle in middle of chain")
35+
36+
# Test 8: Self-loop
37+
assert solution.canFinish(2, [[0, 0]]) == False, "Test 8 failed"
38+
print("✓ Test 8 passed: Self-loop")
39+
40+
# Test 9: Multiple disconnected components, all valid
41+
assert solution.canFinish(4, [[1, 0], [3, 2]]) == True, "Test 9 failed"
42+
print("✓ Test 9 passed: Multiple disconnected components (valid)")
43+
44+
# Test 10: Multiple components, one has cycle
45+
assert solution.canFinish(4, [[1, 0], [3, 2], [2, 3]]) == False, "Test 10 failed"
46+
print("✓ Test 10 passed: Multiple components with cycle")
47+
48+
# Test 11: Large cycle
49+
assert solution.canFinish(5, [[1, 0], [2, 1], [3, 2], [4, 3], [0, 4]]) == False, "Test 11 failed"
50+
print("✓ Test 11 passed: Large cycle")
51+
52+
# Test 12: Diamond dependency (valid)
53+
assert solution.canFinish(4, [[2, 0], [2, 1], [3, 2]]) == True, "Test 12 failed"
54+
print("✓ Test 12 passed: Diamond dependency")
55+
56+
# Test 13: Course with multiple prerequisites
57+
assert solution.canFinish(3, [[2, 0], [2, 1]]) == True, "Test 13 failed"
58+
print("✓ Test 13 passed: Course with multiple prerequisites")
59+
60+
# Test 14: Complex cycle detection
61+
assert solution.canFinish(6, [[1, 0], [2, 1], [3, 2], [1, 3], [4, 3], [5, 4]]) == False, "Test 14 failed"
62+
print("✓ Test 14 passed: Complex cycle detection")
63+
64+
# Test 15: All courses depend on one course
65+
assert solution.canFinish(5, [[1, 0], [2, 0], [3, 0], [4, 0]]) == True, "Test 15 failed"
66+
print("✓ Test 15 passed: All courses depend on one")
67+
68+
# Test 16: Many courses, no prerequisites
69+
assert solution.canFinish(100, []) == True, "Test 16 failed"
70+
print("✓ Test 16 passed: Many courses, no prerequisites")
71+
72+
# Test 17: Duplicate prerequisites (should still work)
73+
assert solution.canFinish(2, [[1, 0], [1, 0]]) == True, "Test 17 failed"
74+
print("✓ Test 17 passed: Duplicate prerequisites")
75+
76+
# Test 18: Course 0 depending on itself through chain
77+
assert solution.canFinish(3, [[1, 0], [2, 1], [0, 2]]) == False, "Test 18 failed"
78+
print("✓ Test 18 passed: Indirect self-dependency")
79+
80+
print("\n" + "="*50)
81+
print("All tests passed! ✓")
82+
print("="*50)
83+
84+
85+
if __name__ == "__main__":
86+
test_course_schedule()

0 commit comments

Comments
 (0)