PS/BFS & DFS

Leetcode 207: Course Schedule (Python)

닻과매 2021. 11. 28. 17:44

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.

  • For example, the pair [0, 1], indicates that to take course 0 you have to first take course 1.

Return true if you can finish all courses. Otherwise, return false.

 

Example 1:

Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take. 
To take course 1 you should have finished course 0. So it is possible.

Example 2:

Input: numCourses = 2, prerequisites = [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take. 
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.

 

Constraints:

  • 1 <= numCourses <= 105
  • 0 <= prerequisites.length <= 5000
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • All the pairs prerequisites[i] are unique.

 


 

풀이

순환구조(1을 들으려면 2를 들어야 하고, 2를 들으려면 3을 들어야 하고, 3을 들으려면 1을 들어야하는 등...)만 없다면 모든 수업을 다 들을 수 있다.

그래서, dfs를 돌리되 순한 구조가 있는지 확인하는 과정을 거치면 된다.

다만, 방문한(=들을 수 있다고 확인한) 수업에 대해서는 다시 방문했을 때 그냥 넘어가도록 처리해준다.

 

 

코드

('파이썬 알고리즘 인터뷰' 책에서 거의 모든 부분을 참고하였음. 나중에 복습하자.)

import collections
from typing import List


class Solution:

	def canFinish2(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        graph = collections.defaultdict(list)
        for x, y in prerequisites:
            graph[x].append(y)
        
        traced, visited = set(), set()
        
        def dfs(i):
            if i in traced:
                return False
            
            if i in visited:
                return True
            
            traced.add(i)
            # graph[i]가 빈 경우(==선수과목이 없는 경우) -> 실행이 안 되고 True return
            # 나머지 경우: 선수과목을 불러옴, loop가 있을 경우, traced에 남아있어서 적발
            for y in graph[i]:
                if not dfs(y):
                    return False
            traced.remove(i)
            
            visited.add(i)
            return True
        
        for x in list(graph):
            if not dfs(x):
                return False
            
        return True