[LeetCode in Python] 207 (M) course schedule 课程表

题目

https://leetcode-cn.com/problems/course-schedule/

你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?

示例 1:

输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。

示例 2:

输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
 
提示:

输入的先决条件是由 边缘列表 表示的图形,而不是 邻接矩阵 。详情请参见图的表示法。
你可以假定输入的先决条件中没有重复的边。
1 <= numCourses <= 10^5

解题思路

本题其实就是在图中找环。

  • Topological Sorting 拓扑排序
  • 先根据课程先后顺序构建图
  • 初始化课程状态数组,初始化为未访问
  • 状态分3种:未访问,访问中,已访问
  • 遍历图的全部节点,在每个节点上进行DFS
  • DFS进来后查看状态数组,
    • 如果当前节点状态为访问中,说明有环,返回False
    • 如果当前节点状态为已访问,说明不需要继续了,返回True
    • 剩余状态就是未访问,
      • 先将本节点状态设置为访问中
      • 如果本节点还有后续节点,则遍历后续节点,在每个节点上DFS并检查返回值
      • 最后将本节点状态置为已访问
  • 如果有环,上面的流程就会返回False,否则返回True

代码

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        # - build graph
        g = defaultdict(list)
        for a,b in prerequisites:
            g[b].append(a)

        # - course status
        # - 0: unvisited, 1: visiting, 2: visited
        status_list = [0] * numCourses

        # - dfs
        def dfs(course):
            # - if the course is in visiting, means loop found
            if status_list[course] == 1: return False

            # - if the course is visited, it is ok
            if status_list[course] == 2: return True

            # - set status as visiting
            status_list[course] = 1

            # - traverse all next courses if has them
            if course in g:
                for c in g[course]:
                    if not dfs(c): return False

            # - set status as visited
            status_list[course] = 2

            return True

        # - check all courses
        for course in g:
            if not dfs(course): 
                return False

        return True

猜你喜欢

转载自www.cnblogs.com/journeyonmyway/p/12702667.html