algorithmic-studies/leetcode/leetcode_210.py

104 lines
3.0 KiB
Python

from collections import deque
class Solution(object):
def __init__(self):
self.scores = None
def findOrder(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: List[int]
"""
if numCourses <= 0:
return []
if not prerequisites:
return range(0,numCourses)
all_courses = range(0, numCourses)
self_references = map(
lambda c: self.has_self_reference(prerequisites, c),
all_courses
)
if any(self_references):
return []
self.scores = numCourses * [-1]
courses = []
for course in all_courses:
score = self.compute_score(prerequisites, course)
if score < 0:
return []
courses.append((score, course))
ordered_courses = sorted(courses)
return [c[1] for c in ordered_courses]
def has_self_reference(self, prerequisites, origin):
# import pdb
# pdb.set_trace()
visited = [origin]
destinations = deque([p[0] for p in prerequisites if p[1] == origin])
while destinations:
d = destinations.popleft()
if d in visited:
return True
visited.append(d)
destinations.extend([p[0] for p in prerequisites
if p[1] == d
and p[0] not in destinations
])
return False
def compute_score(self, prerequisites, course):
if self.scores[course] < 0:
course_prerequisites = [pre[1] for pre in prerequisites
if pre[0] == course]
if not course_prerequisites:
course_score = 0
else:
course_score = len(course_prerequisites) + sum(map(lambda c:
self.compute_score(prerequisites, c),
course_prerequisites
))
self.scores[course] = course_score
return self.scores[course]
import unittest
class SolutionTestCase(unittest.TestCase):
def setUp(self):
self.solution = Solution()
def test_cyclic(self):
self.assertEquals(
[0, 1, 2, 3],
sorted(self.solution.findOrder(4, [[3, 2], [3, 1], [2, 0], [1, 0]]))
)
def test_failure(self):
self.assertEquals(
[],
self.solution.findOrder(3, [[1,0],[0,2],[2,1]])
)
def test_failure_simple(self):
self.assertEquals(
[1, 0],
self.solution.findOrder(2, [[0,1]])
)
def test_failure_other(self):
self.assertEquals(
[5,4,6,3,2,0,7,1],
self.solution.findOrder(8, [[1,0],[2,6],[1,7],[6,4],[7,0],[0,5]])
)
def test_failure_and_another(self):
self.assertEquals(
[],
self.solution.findOrder(3, [[0,2], [1,2], [2,0]])
)
if __name__ == '__main__':
unittest.main()