https://leetcode.com/problems/course-schedule-ii/
코드설명
위상정렬(TopologicalSort)을 활용합니다.
DFS를 활용하여 위상정렬을 구현하는 것은 어렵지 않습니다.
중요한점은, 어디에서 시작하든지 간에 위상정렬을 구할 수 있기에, inDegree를 계산할 필요가 없다는점을 유의합니다.
그렇게 처리함으로써, 더 깊은 이해가 가능해집니다.
하지만, 사이클 판명 부분에서 어려움을 겪었습니다.
예시 2번의, order : [0, 2, 1, 3] 의 정렬을 구했다고 가정하겠습니다.
이때 이러한 위상 정렬이 의미하는 것은, 순서대로 그래프가 DAG(Directed ACyclic Graph)의 순서를 나타냄을 알 수 있습니다.
그러므로, 뒤의 순서에 있는 그래프의 정점이 앞에 있는 그래프를 바라보는것은, "사이클"이 존재한다고 할 수 있습니다.
아래의 코드를 통해, 사이클일 경우 빈 배열을 반환합니다.
for(int i=0; i<NumCourses; i++){ for(int j=i+1; j<NumCourses; j++){ ArrayList<Integer> graphOfJ = graph.get(order.get(j)); for(int k=0; k<graphOfJ.size(); k++){ if(order.get(i) == graphOfJ.get(k)){ return new ArrayList<Integer>(); } } } }
코드
정답코드1입니다.
class Solution { boolean[] seen; ArrayList<ArrayList<Integer>> graph; ArrayList<Integer> order; int NumCourses; int[][] Prerequisites; public int[] findOrder(int numCourses, int[][] prerequisites) { NumCourses = numCourses; Prerequisites = prerequisites; graph = new ArrayList<ArrayList<Integer>>(); for(int i=0; i<numCourses; i++){ graph.add(new ArrayList<Integer>()); } for(int i=0; i<Prerequisites.length; i++){ int a = Prerequisites[i][0]; int b = Prerequisites[i][1]; graph.get(b).add(a); } List<Integer> sorted = topologicalSort(); int[] answer = new int[sorted.size()]; for(int i=0; i<sorted.size(); i++){ answer[i] = sorted.get(i); } return answer; } void DFS(int here){ seen[here] = true; ArrayList<Integer> connected = graph.get(here); for(int i=0; i<connected.size(); i++){ if(seen[connected.get(i)] == false){ DFS(connected.get(i)); } } order.add(here); } List<Integer> topologicalSort(){ seen = new boolean[NumCourses]; order = new ArrayList<Integer>(); for(int i=0; i<NumCourses; i++){ if(seen[i] == false){ DFS(i); } } Collections.reverse(order); for(int i=0; i<NumCourses; i++){ for(int j=i+1; j<NumCourses; j++){ //j번째가 i를 바라보는경우가 있을경우 실패입니다. ArrayList<Integer> graphOfJ = graph.get(order.get(j)); for(int k=0; k<graphOfJ.size(); k++){ if(graphOfJ.get(k) == order.get(i)){ return new ArrayList<>(); } } } } return order; } }
처음에 작성한 오답크도1입니다.
정답이 맞아보이지만,
numCourses = 3, prerequisite = [[1, 0], [1, 2], [0, 1]] 에 대해서 일종의 사이클이 발생하여 [] 를 반환해야합니다.
보시면 알겠지만, 1번 Course 수업을 듣기 위해서는 0번 수업을 듣고 들어야하고, 0번 수업을 듣기 위해서는 1번 수업을 듣고 들어야 합니다. 불가능한 경우라는 것을 알 수 있습니다.
class Solution { ArrayList<ArrayList<Integer>> graph = new ArrayList<>(); int[] inDegree; public int[] findOrder(int numCourses, int[][] prerequisites) { visited = new boolean[numCourses]; for(int i=0; i<numCourses; i++){ graph.add(new ArrayList<Integer>()); } inDegree = new int[numCourses]; for(int i=0; i<prerequisites.length; i++){ int a = prerequisites[i][0];//진입차수 위치 int b = prerequisites[i][1];//진출차수 위치 graph.get(b).add(a); inDegree[a] += 1; } int startIdx = 0; for(int i=0; i<inDegree.length; i++){ //inDegree는 if(inDegree[i] == 0){ startIdx = i; DFS(startIdx); } } Collections.reverse(ret); int[] answer = new int[ret.size()]; int idx = 0; for(int v : ret){ answer[idx++] = v; } return answer; } List<Integer> ret = new ArrayList<Integer>(); boolean[] visited; public void DFS(int idx){ ArrayList<Integer> node = graph.get(idx); for(int i=0; i<node.size(); i++){ int next = node.get(i); if(visited[next] == false){ visited[next] = true; DFS(next); } } ret.add(idx); } }