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);
}
}