๐ง DAG๋?
DAG(Directed Acyclic Graph)๋ ์ฌ์ดํด์ด ์กด์ฌํ์ง ์๋ ๋ฐฉํฅ ๊ทธ๋ํ์ ๋๋ค. ์ด ๊ตฌ์กฐ๋ ์ด๋ฒคํธ ๊ฐ์ ์ ํ ๊ด๊ณ๋ฅผ ํ์ ํด์ผ ํ๋ ๋ฌธ์ ์์ ๋งค์ฐ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด, ๊ณผ๋ชฉ ์๊ฐ ์์๋ฅผ ์ ํ๋ ๋ฌธ์ ์์ ํ์ ์ ์ด์ ๊ณผ๋ชฉ์ด ์๋ค๋ฉด ๊ทธ ๊ด๊ณ๋ฅผ DAG๋ก ํํํ ์ ์์ต๋๋ค.
๋ํ ๋ฌธ์ : LeetCode - Course Schedule II
โ ๋น์ํ ๊ทธ๋ํ

โ ์ํ ๊ทธ๋ํ

์์ ์ ๋ ฌ(Topological Sort)์ด๋?
์ ์: DAG(Directed Acyclic Graph)์ ๋ ธ๋๋ฅผ ์ ํ(linear) ์์๋ก ๋์ดํ๋ ์ ๋ ฌ ๋ฐฉ์์ ๋๋ค.
์ ๋ ฌ๋ ๊ฒฐ๊ณผ๋ ๋ชจ๋ ๊ฐ์ (a → b)์ ๋ํด a๊ฐ b๋ณด๋ค ์์๋๋ก ๋ณด์ฅํฉ๋๋ค.
๋ฐ๋ผ์, ๊ทธ๋ํ์ ์ฌ์ดํด์ด ์๋ค๋ฉด ์์ ์ ๋ ฌ์ ์ํ๋ ์ ์์ต๋๋ค.
์ด๋ฅผ ํ๋จํ๊ธฐ ์ํด ์ผ๋ฐ์ ์ผ๋ก DFS ๋๋ BFS(Kahn’s Algorithm) ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๐ ๏ธ ๊ตฌํ ๋ฐฉ๋ฒ (BFS - Kahn's Algorithm)
- ํ์ ๊ตฌ์ฑ ์์:
- in-degree ๋ฐฐ์ด: ๊ฐ ๋ ธ๋์ ๋ค์ด์ค๋ ๊ฐ์ ์ ์ ์ฅ
- ๊ทธ๋ํ ์ธ์ ๋ฆฌ์คํธ: ๊ฐ ๋ ธ๋๊ฐ ๊ฐ๋ฆฌํค๋ ๋ ธ๋ ๋ฆฌ์คํธ
- Queue: in-degree๊ฐ 0์ธ ๋ ธ๋๋ฅผ ์ฒ๋ฆฌ
- ๊ฒฐ๊ณผ ๋ฆฌ์คํธ: ์์ ์ ๋ ฌ๋ ๋ ธ๋ ์ ์ฅ
- ์ ์ฒด ๊ณผ์ :
- ๋ชจ๋ ๋ ธ๋์ in-degree ๊ณ์ฐ
- in-degree๊ฐ 0์ธ ๋ ธ๋๋ค์ Queue์ ์ฝ์
- Queue์์ ๋
ธ๋๋ฅผ ํ๋์ฉ ๊บผ๋ด๊ณ :
- ๊ฒฐ๊ณผ ๋ฆฌ์คํธ์ ์ถ๊ฐ
- ํด๋น ๋ ธ๋์์ ์ด์ด์ง๋ ๊ฐ์ ์ ๊ฑฐ (in-degree ๊ฐ์)
- in-degree๊ฐ 0์ด ๋ ๋ ธ๋๋ฅผ Queue์ ์ถ๊ฐ
- ๋ชจ๋ ๋ ธ๋๋ฅผ ์ฒ๋ฆฌํ์ ๋ ๊ฒฐ๊ณผ ๋ฆฌ์คํธ์ ํฌ๊ธฐ๊ฐ ์ ์ฒด ๋ ธ๋ ์์ ๊ฐ๋ค๋ฉด ์ฑ๊ณต์ ์ธ ์์ ์ ๋ ฌ, ์๋๋ผ๋ฉด ์ฌ์ดํด ์กด์ฌ
์๋๋ ์์ ์ฝ๋์ ๋๋ค.
class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
// Create adjacency list for graph representation
List<Integer>[] courseSet = new ArrayList[numCourses];
int[] inDegree = new int[numCourses]; // Track the in-degrees (number of incoming edges)
// Build the graph
for (int i = 0; i < prerequisites.length; i++) {
int course = prerequisites[i][0];
int prereq = prerequisites[i][1];
if (courseSet[prereq] == null) {
courseSet[prereq] = new ArrayList<>();
}
// Add an edge from prereq to course (correct direction)
courseSet[prereq].add(course);
inDegree[course]++; // Increment the in-degree of the course
}
Queue<Integer> queue = new LinkedList<>(); //Look for starting node
for (int i = 0; i < numCourses; i++) {
if (inDegree[i] == 0) {
queue.add(i);
}
}
int[] result = new int[numCourses];
int index = 0;
while (!queue.isEmpty()) {
Integer courseNum = queue.poll(); //start
result[index++] = courseNum; //append result
//Now, get the next course
if (courseSet[courseNum] != null) {
List<Integer> nextCourses = courseSet[courseNum];
for (Integer nextCourse : nextCourses) {
inDegree[nextCourse]--; //reduce indegree count if visited
if (inDegree[nextCourse] == 0) {
queue.add(nextCourse);
}
}
}
}
// Check if topological sort was possible, if incremented index is same as provided numCourses
return index == numCourses ? result : new int[0];
}
}
โฑ๏ธ ์๊ฐ ๋ณต์ก๋ ๋ถ์
- ์๊ฐ ๋ณต์ก๋: O(V + E)
- V: ๋ ธ๋ ์ (numCourses)
- E: ๊ฐ์ ์ (prerequisites.length)
- ๊ณต๊ฐ ๋ณต์ก๋: O(V + E)
- ์ธ์ ๋ฆฌ์คํธ ๋ฐ in-degree ๋ฐฐ์ด ์ ์ฅ ๊ณต๊ฐ
โ
๋ง๋ฌด๋ฆฌ ์์ฝ
- DAG๋ ์ฌ์ดํด์ด ์๋ ๋ฐฉํฅ ๊ทธ๋ํ์ด๋ฉฐ, ์ ํ ๊ด๊ณ๊ฐ ํ์ํ ๋ฌธ์ ์ ์ ํฉํฉ๋๋ค.
- ์์ ์ ๋ ฌ์ DAG์ ์ ์ ์ ์ ํ์ผ๋ก ๋์ดํ๋ ๊ธฐ๋ฒ์ ๋๋ค
- Kahn’s Algorithm์ BFS ๊ธฐ๋ฐ์ ์์ ์ ๋ ฌ๋ก, ์ฌ์ดํด ํ์ง์๋ ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค