https://leetcode.com/discuss/general-discussion/460599/blind-75-leetcode-questions
위의 링크에서 Graph 카테고리에 있는 문제를 풀어보았다.
이 문제를 풀기위해서는 일단 그래프라는 자료 구조가 무엇인지, 그래프를 구현하는 방법에는 무엇이 있는지 알아야한다.
노드(node) 와 그 노드를 연결하는 간선(edge)으로 이루어진 자료구조
cf) 트리 또한 cycle이 허용되지 않는 그래프이다.
node는 다른 말로 vertex라고도 불린다.
아래와 같이 간선의 방향성에 따라 두가지로 나눌 수 있다.
아래 예시는 방향 그래프와 그것을 구현한 인접 행렬을 나타낸다.
길이 존재할 때는 1, 존재하지 않으면 0으로 표현된다.
그래프에서 0->1로 가는 길이 존재하기 때문에 matrix[0,1] = 1이다. 반대로, 1->0은 존재하지 않기 때문에 행렬에서 [1,0] = 0이다.
BFS로 수업들을 하나하나 확인한다. 확인하면서 visited라는 변수에 몇개의 수업을 확인했는지 체크한다. 그래프를 다 돌고 난 후 visited와 주어진 수업들의 개수가 다르다면 cycle이 있는 것이므로 false, 같다면 cycle이 없는 것이므로 true를 리턴한다.
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
# 인접 리스트를 만든다.
# course는 0~numCourses-1 사이의 숫자들이므로
# adj[i]는 course i를 듣고 나서 들을 수 있는 수업들이다.
adj = [[] for _ in range(numCourses)]
# degree라는 리스트를 만든다.
# degree[i]는 현재 수업을 듣기전에 들어야하는 수업들, 즉
# prerequisites의 개수이다.
degree = [0] * numCourses
for (curr, pre) in prerequisites:
adj[pre].append(curr)
degree[curr] += 1
# queue를 만든다.
queue = collections.deque([])
# queue에 prerequisite이 필요하지 않은 수업을 저장한다.
for v in range(numCourses):
if degree[v] == 0:
queue.append(v)
# 몇개의 수업을 들었는지 track한다.
visited = 0
while queue:
# 지금 current class 확인
curr = queue.popleft()
# mark as visited
visited += 1
# adj[curr], 즉 curr course를 듣고 난 후
# 들을 수 있는 수업들을 확인한다
for dep in adj[curr]:
degree[dep] -= 1
# degree를 없애는 것은 graph에서 curr 수업을 들었으니 더 확인할
# 필요가 없으므로 삭제
# 만약 degree를 없애고 난 후에 degree = 0이면,
if not degree[dep]:
# queue에 지금 확인한 dep을 저장하고 또 확인하러 간다
queue.append(dep)
# 확인한 수업들의 개수 == 총 수업 개수가 같으면 cycle이 없는 것이다.
return visited == numCourses