|
| 1 | +/** |
| 2 | + * https://leetcode.com/problems/course-schedule/description/ |
| 3 | + * @param {number} numCourses |
| 4 | + * @param {number[][]} prerequisites |
| 5 | + * @return {boolean} |
| 6 | + */ |
| 7 | +var canFinish = function (numCourses, prerequisites) { |
| 8 | + if (numCourses === 1) return true; // 과목이 1개면 무조건 수강 가능 |
| 9 | + |
| 10 | + let adjList = new Map(); // 각 과목에 대해 선행 과목들을 저장하는 인접 리스트 |
| 11 | + let visited = new Set(); // 이미 수강 가능한 것으로 확인된 과목들 |
| 12 | + let path = new Set(); // 현재 DFS 경로에 포함된 과목들 (사이클 확인용) |
| 13 | + |
| 14 | + // 모든 과목을 인접 리스트에 초기화 |
| 15 | + for (let i = 0; i < numCourses; i++) { |
| 16 | + adjList.set(i, []); |
| 17 | + } |
| 18 | + |
| 19 | + // prerequisite 정보를 기반으로 인접 리스트 구성 |
| 20 | + for (let i = 0; i < prerequisites.length; i++) { |
| 21 | + // [0, 1]은 0을 듣기 위해 1을 먼저 들어야 함 |
| 22 | + adjList.get(prerequisites[i][0]).push(prerequisites[i][1]); |
| 23 | + } |
| 24 | + |
| 25 | + // DFS 함수: 해당 course를 수강할 수 있는지 확인 |
| 26 | + const canTake = (course) => { |
| 27 | + if (visited.has(course)) return true; // 이미 확인된 코스는 재확인 필요 없음 |
| 28 | + if (path.has(course)) return false; // 현재 DFS 경로에 course가 있다면 사이클 발생 |
| 29 | + |
| 30 | + path.add(course); // 현재 경로에 course 추가 |
| 31 | + |
| 32 | + let preCourses = adjList.get(course); // course를 듣기 위한 선행 과목들 |
| 33 | + for (let i = 0; i < preCourses.length; i++) { |
| 34 | + if (!canTake(preCourses[i])) return false; // 선행 과목 중 하나라도 불가능하면 종료 |
| 35 | + } |
| 36 | + |
| 37 | + path.delete(course); // 경로에서 제거 (백트래킹) |
| 38 | + visited.add(course); // 수강 가능한 것으로 확인 |
| 39 | + return true; |
| 40 | + }; |
| 41 | + |
| 42 | + // 모든 과목에 대해 수강 가능한지 확인 |
| 43 | + for (let i = 0; i < numCourses; i++) { |
| 44 | + path = new Set(); // 새로운 DFS 탐색이므로 경로 초기화 |
| 45 | + if (!canTake(i)) return false; // 한 과목이라도 못 들으면 false |
| 46 | + } |
| 47 | + |
| 48 | + return true; // 모든 과목 수강 가능 |
| 49 | +}; |
0 commit comments