diff --git a/course-schedule/byol-han.js b/course-schedule/byol-han.js new file mode 100644 index 000000000..cf6ec99bd --- /dev/null +++ b/course-schedule/byol-han.js @@ -0,0 +1,49 @@ +/** + * https://leetcode.com/problems/course-schedule/description/ + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {boolean} + */ +var canFinish = function (numCourses, prerequisites) { + if (numCourses === 1) return true; // 과목이 1개면 무조건 수강 가능 + + let adjList = new Map(); // 각 과목에 대해 선행 과목들을 저장하는 인접 리스트 + let visited = new Set(); // 이미 수강 가능한 것으로 확인된 과목들 + let path = new Set(); // 현재 DFS 경로에 포함된 과목들 (사이클 확인용) + + // 모든 과목을 인접 리스트에 초기화 + for (let i = 0; i < numCourses; i++) { + adjList.set(i, []); + } + + // prerequisite 정보를 기반으로 인접 리스트 구성 + for (let i = 0; i < prerequisites.length; i++) { + // [0, 1]은 0을 듣기 위해 1을 먼저 들어야 함 + adjList.get(prerequisites[i][0]).push(prerequisites[i][1]); + } + + // DFS 함수: 해당 course를 수강할 수 있는지 확인 + const canTake = (course) => { + if (visited.has(course)) return true; // 이미 확인된 코스는 재확인 필요 없음 + if (path.has(course)) return false; // 현재 DFS 경로에 course가 있다면 사이클 발생 + + path.add(course); // 현재 경로에 course 추가 + + let preCourses = adjList.get(course); // course를 듣기 위한 선행 과목들 + for (let i = 0; i < preCourses.length; i++) { + if (!canTake(preCourses[i])) return false; // 선행 과목 중 하나라도 불가능하면 종료 + } + + path.delete(course); // 경로에서 제거 (백트래킹) + visited.add(course); // 수강 가능한 것으로 확인 + return true; + }; + + // 모든 과목에 대해 수강 가능한지 확인 + for (let i = 0; i < numCourses; i++) { + path = new Set(); // 새로운 DFS 탐색이므로 경로 초기화 + if (!canTake(i)) return false; // 한 과목이라도 못 들으면 false + } + + return true; // 모든 과목 수강 가능 +}; diff --git a/invert-binary-tree/byol-han.js b/invert-binary-tree/byol-han.js new file mode 100644 index 000000000..2775f8a0e --- /dev/null +++ b/invert-binary-tree/byol-han.js @@ -0,0 +1,21 @@ +/** + * https://leetcode.com/problems/invert-binary-tree/submissions/1651537941/ + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {TreeNode} + */ +var invertTree = function (root) { + if (root === null) return null; + + // 왼쪽과 오른쪽 자식 노드 바꾸기 + [root.left, root.right] = [invertTree(root.right), invertTree(root.left)]; + + return root; +}; diff --git a/jump-game/byol-han.js b/jump-game/byol-han.js new file mode 100644 index 000000000..92b0b2b2a --- /dev/null +++ b/jump-game/byol-han.js @@ -0,0 +1,26 @@ +/** + * https://leetcode.com/problems/jump-game/description/ + * @param {number[]} nums + * @return {boolean} + */ +var canJump = function (nums) { + let maxReach = 0; // 현재까지 도달할 수 있는 최대 인덱스 + + for (let i = 0; i < nums.length; i++) { + // 현재 위치가 도달 가능한 최대 거리보다 멀다면 끝에 도달할 수 없음 + if (i > maxReach) { + return false; + } + + // 현재 위치에서 갈 수 있는 최대 위치 업데이트 + maxReach = Math.max(maxReach, i + nums[i]); + + // 최종 목적지에 도달 가능하면 true 바로 반환 + if (maxReach >= nums.length - 1) { + return true; + } + } + + // 반복문 끝나도 못 도달한 경우 + return false; +}; diff --git a/merge-k-sorted-lists/byol-han.js b/merge-k-sorted-lists/byol-han.js new file mode 100644 index 000000000..9f218f2f9 --- /dev/null +++ b/merge-k-sorted-lists/byol-han.js @@ -0,0 +1,49 @@ +/** + * https://leetcode.com/problems/merge-k-sorted-lists/description/ + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode[]} lists + * @return {ListNode} + */ +var mergeKLists = function (lists) { + if (lists.length === 0) { + return null; + } + + while (lists.length > 1) { + const merged = []; + const size = lists.length; + + for (let i = 0; i < size; i += 2) { + const l1 = lists[i]; + const l2 = i + 1 < lists.length ? lists[i + 1] : null; + merged.push(mergeLists(l1, l2)); + } + + lists = merged; + } + + return lists[0]; +}; + +function mergeLists(l1, l2) { + const head = new ListNode(0); + let cur = head; + while (l1 !== null && l2 !== null) { + if (l1.val < l2.val) { + cur.next = l1; + l1 = l1.next; + } else { + cur.next = l2; + l2 = l2.next; + } + cur = cur.next; + } + cur.next = l1 === null ? l2 : l1; + return head.next; +} diff --git a/search-in-rotated-sorted-array/byol-han.js b/search-in-rotated-sorted-array/byol-han.js new file mode 100644 index 000000000..df34c0c82 --- /dev/null +++ b/search-in-rotated-sorted-array/byol-han.js @@ -0,0 +1,47 @@ +/** + * https://leetcode.com/problems/search-in-rotated-sorted-array/ + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var search = function (nums, target) { + let left = 0; + let right = nums.length - 1; + + // Continue searching while the window is valid + while (left <= right) { + // Find the middle index + let mid = Math.floor((left + right) / 2); + + // If the target is found at mid, return the index + if (nums[mid] === target) { + return mid; + } + + // Check if the left half is sorted + if (nums[left] <= nums[mid]) { + // If target is in the range of the sorted left half + if (nums[left] <= target && target < nums[mid]) { + // Move the right pointer to just before mid + right = mid - 1; + } else { + // Target must be in the right half + left = mid + 1; + } + + // Otherwise, the right half must be sorted + } else { + // If target is in the range of the sorted right half + if (nums[mid] < target && target <= nums[right]) { + // Move the left pointer to just after mid + left = mid + 1; + } else { + // Target must be in the left half + right = mid - 1; + } + } + } + + // If the loop ends, target is not in the array + return -1; +};