|
| 1 | +from collections import deque |
| 2 | +from typing import List |
| 3 | +from unittest import TestCase, main |
| 4 | + |
| 5 | + |
| 6 | +class Solution: |
| 7 | + def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: |
| 8 | + return self.solve_topological_sort(numCourses, prerequisites) |
| 9 | + |
| 10 | + """ |
| 11 | + Runtime: 1 ms (Beats 100.00%) |
| 12 | + Time Complexity: o(c + p) |
| 13 | + - graph 및 rank 갱신에 prerequisites의 길이 p만큼 조회하는데 O(p) |
| 14 | + - queue의 초기 노드 삽입에 numCourses만큼 조회하는데 O(c) |
| 15 | + - queue에서 위상 정렬로 탐색하는데 모든 노드와 간선을 조회하는데 O(c + p) |
| 16 | + > O(p) + O(c) + O(c + p) ~= o(c + p) |
| 17 | +
|
| 18 | + Memory: 17.85 MB (Beats 99.94%) |
| 19 | + Space Complexity: O(c) |
| 20 | + - graph 변수 사용에 O(c) |
| 21 | + - rank 변수 사용에 O(c) |
| 22 | + - queue 변수 사용에서 최대 크기는 graph의 크기와 같으므로 O(c) |
| 23 | + > O(c) + O(c) + O(c) ~= O(c) |
| 24 | + """ |
| 25 | + def solve_topological_sort(self, numCourses: int, prerequisites: List[List[int]]) -> bool: |
| 26 | + graph = {i: [] for i in range(numCourses)} |
| 27 | + rank = [0] * numCourses |
| 28 | + for u, v in prerequisites: |
| 29 | + graph[v].append(u) |
| 30 | + rank[u] += 1 |
| 31 | + |
| 32 | + queue = deque() |
| 33 | + for i in range(numCourses): |
| 34 | + if rank[i] == 0: |
| 35 | + queue.append(i) |
| 36 | + |
| 37 | + count = 0 |
| 38 | + while queue: |
| 39 | + node = queue.popleft() |
| 40 | + count += 1 |
| 41 | + for neighbor in graph[node]: |
| 42 | + rank[neighbor] -= 1 |
| 43 | + if rank[neighbor] == 0: |
| 44 | + queue.append(neighbor) |
| 45 | + |
| 46 | + return count == numCourses |
| 47 | + |
| 48 | + |
| 49 | +class _LeetCodeTestCases(TestCase): |
| 50 | + def test_1(self): |
| 51 | + numCourses = 5 |
| 52 | + prerequisites = [[1,4],[2,4],[3,1],[3,2]] |
| 53 | + output = True |
| 54 | + self.assertEqual(Solution.canFinish(Solution(), numCourses, prerequisites), output) |
| 55 | + |
| 56 | + |
| 57 | +if __name__ == '__main__': |
| 58 | + main() |
0 commit comments