104 lines
3.0 KiB
Python
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()
|