算法练习 Leetcode 力扣 207. Course Schedule 解法

这题以前觉得特别难,其实是简化版的topological sort,也就是只需要判断有没有环(circular dependency)和省掉了sort部分。可以用269 alien dictionary同样的DFS思路加以简化而成。

这是最近写得比较满意的python解法。

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        edges = {c: set() for c in range(numCourses)}
        for prereq in prerequisites:
            edges[prereq[1]].add(prereq[0])
        
        seen = {}
        
        def dfs(start):
            if start in seen:
                return seen[start]
            seen[start] = False
            for nxt in edges[start]:
                if not dfs(nxt):
                    return False
            seen[start] = True
            return True
        
        if not all(dfs(start) for start in range(numCourses)):
            return False
        return True

对比一下大概半年前写得当时比较满意版本,其实算法差不多。有如下小改进让code更短了:
1. seen用了Tree和False表示走通了的和当前正在走的路径,比原来的更省事。看来2种状态是判断环和避免重新走原来走过的路所必要的。
2. 节点全部写进edges里面,edges = {c: set() for c in range(numCourses)} ,不管有没有dependency,省了 if i not in deps: 判断
3. 需要order的话,dfs参数start, edges, seen order。不需要的话order的话就省掉order,只要start, edges, seen。用函数内定义函数可以少写很多用来传递状态的参数。

class Solution(object):
    def __init__(self):
        self.UNKNOWN = 0
        self.VISITED = 1
        self.CANTAKE = 2
        
    def canFinish(self, numCourses, prerequisites):
        """
        :type numCourses: int
        :type prerequisites: List[List[int]]
        :rtype: bool
        """
        deps = {}
        for pre in prerequisites:
            if pre[0] in deps:
                deps[pre[0]].add(pre[1])
            else:
                deps[pre[0]] = {pre[1]}
                
        status = [self.UNKNOWN] * numCourses
        for i in range(numCourses):
            if self.okToTake(i, status, deps) == False:
                return False
        return True
        
    def okToTake(self, i, status, deps):
        if status[i] == self.CANTAKE:
            return True
        elif status[i] == self.VISITED:
            return False
        status[i] = self.VISITED
        if i not in deps:
            status[i] = self.CANTAKE
            return True
        for dep in deps[i]:
            if self.okToTake(dep, status, deps) == False:
                return False
        status[i] = self.CANTAKE
        return True
    

Leave a Comment

Your email address will not be published.