Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions 0210.Course-Schedule-II/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 210. Course Schedule II

## step1
最初集合で先祖を管理しようとしたが、閉路検出ができないことに気づき、statusを使う方針に書き換えた。
19mほど。

## 他の人のコードなど

> DFSのトポロジカルソートですが、preorder(行きがけ)でTEMPORARYとマークか、すでにTEMPORARYなら、サイクルと判定。postorder(帰りがけ)でPERMANENTとマークするみたいな感じですね。

https://github.com/potrue/leetcode/pull/77/changes

入次数で管理するやり方。Kahnのアルゴリズムというものだった。他の問題で見た覚えがあるが使えなかった。

https://ja.wikipedia.org/wiki/%E3%83%88%E3%83%9D%E3%83%AD%E3%82%B8%E3%82%AB%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88

Kahnのアルゴリズムを書くのはBFS, DFSどちらでも可能だがBFSで実装する。

## step2
変数名を具体的にする
34 changes: 34 additions & 0 deletions 0210.Course-Schedule-II/step1_dfs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class Solution:
def findOrder(self, numCourses: int, prerequisites: list[list[int]]) -> list[int]:
adjacent_list = [[] for _ in range(numCourses)]
for second, first in prerequisites:
adjacent_list[first].append(second)

order = []
# 0: 未訪問, 1: 訪問中, 2: 訪問ずみ

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

マジックナンバーとなっているのが気になりました。 enum の仕様をお勧めいたします。
https://docs.python.org/ja/3/library/enum.html

status = [0] * numCourses

def dfs(i):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

関数名は通常英単語の原形または命令形、もしくは助動詞などで始まることが多いと思います。また、関数名にはその関数が何をするのか、何が返ってくるのかを表す英単語・英語句を付けることをお勧めいたします。 dfs は実装の詳細に深入りしすぎているように感じます。 visit_course や can_finish_from などはいかがでしょうか?

if status[i] == 1:
return False
if status[i] == 2:
return True

status[i] = 1
for j in adjacent_list[i]:
can_be_finished = dfs(j)
if not can_be_finished:
return False

status[i] = 2
order.append(i)
return True

for i in range(numCourses):
if status[i] != 0:
continue
can_be_finished = dfs(i)
if not can_be_finished:
return []

return order[::-1]
40 changes: 40 additions & 0 deletions 0210.Course-Schedule-II/step2_dfs_revised.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from enum import IntEnum

class CourseStatus(IntEnum):
NOT_VISITED = 0
VISITING = 1
VISITED = 2

class Solution:
def findOrder(self, numCourses: int, prerequisites: list[list[int]]) -> list[int]:
next_courses = [[] for _ in range(numCourses)]
for second, first in prerequisites:
next_courses[first].append(second)

order = []
status = [CourseStatus.NOT_VISITED] * numCourses

def visit_course(course):
if status[course] == CourseStatus.VISITING:
return False
if status[course] == CourseStatus.VISITED:
return True

status[course] = CourseStatus.VISITING
for next_course in next_courses[course]:
can_be_finished = visit_course(next_course)
if not can_be_finished:
return False

status[course] = CourseStatus.VISITED
order.append(course)
return True

for course in range(numCourses):
if status[course] != CourseStatus.NOT_VISITED:
continue
can_be_finished = visit_course(course)
if not can_be_finished:
return []

return order[::-1]
29 changes: 29 additions & 0 deletions 0210.Course-Schedule-II/step2_kahn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import collections

class Solution:
def findOrder(self, numCourses: int, prerequisites: list[list[int]]) -> list[int]:
adjacent_list = [[] for _ in range(numCourses)]
in_degree = [0] * numCourses
for second, first in prerequisites:
adjacent_list[first].append(second)
in_degree[second] += 1

queue = collections.deque()
for i in range(numCourses):
if in_degree[i] == 0:
queue.append(i)

order = []
while queue:
i = queue.popleft()
order.append(i)
for j in adjacent_list[i]:
in_degree[j] -= 1
if in_degree[j] == 0:
queue.append(j)

if len(order) != numCourses:
return []
return order


29 changes: 29 additions & 0 deletions 0210.Course-Schedule-II/step2_kahn_revised.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import collections

class Solution:
def findOrder(self, numCourses: int, prerequisites: list[list[int]]) -> list[int]:
next_courses = [[] for _ in range(numCourses)]
in_degree = [0] * numCourses
for second, first in prerequisites:
next_courses[first].append(second)
in_degree[second] += 1

available_courses = collections.deque()
for course in range(numCourses):
if in_degree[course] == 0:
available_courses.append(course)

order = []
while available_courses:
course = available_courses.popleft()
order.append(course)
for next_course in next_courses[course]:
in_degree[next_course] -= 1
if in_degree[next_course] == 0:
available_courses.append(next_course)

if len(order) != numCourses:
return []
return order