|
| 1 | +""" |
| 2 | +https://leetcode.com/problems/course-schedule/ |
| 3 | +
|
| 4 | +문제: 수강 해야 하는 모든 강좌의 수 numCourses가 주어질 때, 모든 강좌를 끝낼 수 있으면 true, 아니면 false를 반환해라. |
| 5 | + prerequisites[i] = [ai, bi], bi를 수강하기 위해선 반드시 ai를 사전 수강해야만 한다. |
| 6 | + |
| 7 | +풀이: 사이클이 있으면 수강 불가능 (순환 참조), 없으면 수강 가능 |
| 8 | + 각 강좌를 Node로 보고, 선행 과목 관계를 방향이 있는 간선(Edge)로 보면 -> 방향 그래프 |
| 9 | + |
| 10 | + BFS 풀이 |
| 11 | + 1. 그래프 만들기 |
| 12 | + graph[a] = [b, c] 이면 a를 듣기 전에 b, c를 들어야 한다. |
| 13 | + graph[b] = [a] 이면 b를 듣기 전에 a를 들어야 한다. |
| 14 | +
|
| 15 | + 2. 진입 차수 계산 |
| 16 | + 진입 차수: 어떤 노드로 들어오는 간선의 수 |
| 17 | + 진입 차수가 0인 노드는 바로 들을 수 있는 강의 |
| 18 | + |
| 19 | + 3. Queue에 진입 차수가 0인 노드부터 넣고 시작 |
| 20 | + Queue에서 꺼낸 노드를 기준으로, 연결된 노드들의 진입차수를 하나씩 줄인다. |
| 21 | + 진입차수가 0이 된 노드는 새로 Queue에 추가 |
| 22 | + |
| 23 | + 4, 처리된 노드 수가 전체 강의 수와 같으면 True, 아니면 False |
| 24 | +
|
| 25 | +TC: O(V + E), V: 과목 수, E: prerequisite 관계 수 |
| 26 | +SC: O(V + E), 그래프 + 진입차수 배열 |
| 27 | +""" |
| 28 | + |
| 29 | +from typing import List |
| 30 | +from collections import defaultdict, deque |
| 31 | + |
| 32 | +class Solution: |
| 33 | + def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: |
| 34 | + graph = defaultdict(list) |
| 35 | + indegree = [0] * numCourses |
| 36 | + |
| 37 | + # 1. 그래프 만들기, 2. 진입차수 계산 |
| 38 | + # 수강 강의, 사전 강의 |
| 39 | + for course, prereq in prerequisites: |
| 40 | + graph[prereq].append(course) |
| 41 | + indegree[course] += 1 |
| 42 | + |
| 43 | + # 3. Queue에 진입 차수가 0인 노드부터 넣고 시작 |
| 44 | + queue = deque([i for i in range(numCourses) if indegree[i] == 0]) |
| 45 | + completed = 0 |
| 46 | + |
| 47 | + # 4. BFS 탐색, 처리된 노드 수가 전체 강의 수와 같으면 True, 아니면 False |
| 48 | + while queue: |
| 49 | + # queue에서 꺼낸 과목을 수강 완료 처리 |
| 50 | + current = queue.popleft() |
| 51 | + completed += 1 |
| 52 | + |
| 53 | + for neighbor in graph[current]: |
| 54 | + indegree[neighbor] -= 1 |
| 55 | + if indegree[neighbor] == 0: |
| 56 | + queue.append(neighbor) |
| 57 | + |
| 58 | + return completed == numCourses |
0 commit comments