Skip to content

Commit 99354cc

Browse files
committed
course-schedule sol (py)
1 parent c985241 commit 99354cc

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

course-schedule/hi-rachel.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,102 @@ def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
5656
queue.append(neighbor)
5757

5858
return completed == numCourses
59+
60+
"""
61+
위상 정렬을 구하는 알고리즘
62+
1. DFS 기반 (스택을 쌓아 뒤집는 방식)
63+
2. Kahn 알고리즘 (진입차수 0부터 차례로 큐 처리)
64+
65+
Kahn 알고리즘이란?
66+
방향 그래프에서 진입차수(indegree)가 0인 정점부터 차례로 제거(큐에 넣어 꺼내기)하며 위상 순서를 만드는 방법.
67+
진입차수가 0인 정점이 하나도 없는데 아직 남은 정점이 있다면 사이클 존재 -> 위상 정렬 불가.
68+
69+
위상 순서: 방향 그래프에서 간선(u→v)이 있다면, 순서에서 u가 항상 v보다 앞에 나오는 정점들의 나열.
70+
진입차수: 정점으로 들어오는 간선의 개수.
71+
72+
73+
TC: O(V + E), V: 과목 수, E: prerequisite 관계 수
74+
SC: O(V + E), 그래프 + 진입차수 배열
75+
"""
76+
class Solution:
77+
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
78+
# 1) 그래프(인접 리스트)와 진입차수 배열 만들기
79+
adj = [[] for _ in range(numCourses)]
80+
indeg = [0] * numCourses
81+
for a, b in prerequisites: # b -> a (b를 먼저 들어야 a를 들을 수 있음)
82+
adj[b].append(a)
83+
indeg[a] += 1
84+
85+
# 2) 진입차수 0인 정점들로 큐 초기화
86+
q = deque([i for i in range(numCourses) if indeg[i] == 0])
87+
taken = 0 # 처리(수강) 완료한 과목 수
88+
89+
# 3) 큐에서 빼며 간선 제거(=후속 과목 진입차수 감소)
90+
while q:
91+
u = q.popleft()
92+
taken += 1
93+
for v in adj[u]:
94+
indeg[v] -= 1
95+
if indeg[v] == 0:
96+
q.append(v)
97+
98+
# 4) 모두 처리됐으면 사이클 없음
99+
return taken == numCourses
100+
101+
102+
"""
103+
DFS 기반
104+
TC: O(V + E), V: 과목 수, E: prerequisite 관계 수
105+
SC: O(V + E), 그래프 + 탐색 중인 과목 집합 + 수강 완료한 과목 집합
106+
"""
107+
class Solution:
108+
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
109+
graph = {i: [] for i in range(numCourses)}
110+
for crs, pre in prerequisites:
111+
# 선수 과목을 원소로 추가
112+
graph[crs].append(pre)
113+
114+
# 탐색중
115+
traversing = set()
116+
# 수강가능한 과목
117+
finished = set()
118+
119+
def can_finish(crs):
120+
if crs in traversing:
121+
return False
122+
if crs in finished:
123+
return True
124+
125+
traversing.add(crs)
126+
for pre in graph[crs]:
127+
if not can_finish(pre):
128+
return False
129+
traversing.remove(crs)
130+
finished.add(crs)
131+
return True
132+
133+
for crs in graph:
134+
if not can_finish(crs):
135+
return False
136+
return True
137+
138+
# 줄인 코드
139+
class Solution:
140+
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
141+
graph = {i: [] for i in range(numCourses)}
142+
for crs, pre in prerequisites:
143+
graph[crs].append(pre)
144+
145+
traversing = set()
146+
147+
@cache
148+
def can_finish(crs):
149+
if crs in traversing:
150+
return False
151+
152+
traversing.add(crs)
153+
result = all(can_finish(pre) for pre in graph[crs])
154+
traversing.remove(crs)
155+
return result
156+
157+
return all(can_finish(crs) for crs in graph)

0 commit comments

Comments
 (0)