diff --git a/coin-change/byol-han.js b/coin-change/byol-han.js new file mode 100644 index 000000000..6026a89eb --- /dev/null +++ b/coin-change/byol-han.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} coins + * @param {number} amount + * @return {number} + */ +var coinChange = function (coins, amount) { + // dp[i]는 금액 i를 만들기 위한 최소 코인 수 + const dp = new Array(amount + 1).fill(Infinity); + + // 금액 0을 만들기 위해 필요한 코인 수는 0개 + dp[0] = 0; + + // 1부터 amount까지 반복 + for (let i = 1; i <= amount; i++) { + // 각 금액마다 모든 코인 시도 + for (let coin of coins) { + if (i - coin >= 0) { + // 코인을 하나 사용했을 때, 남은 금액의 최소 개수 + 1 + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + } + + // 만약 Infinity면 만들 수 없는 금액임 + return dp[amount] === Infinity ? -1 : dp[amount]; +}; diff --git a/find-minimum-in-rotated-sorted-array/byol-han.js b/find-minimum-in-rotated-sorted-array/byol-han.js new file mode 100644 index 000000000..fde21f23a --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/byol-han.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var findMin = function (nums) { + let left = 0; + let right = nums.length - 1; + + while (left < right) { + let mid = Math.floor((left + right) / 2); + + if (nums[mid] > nums[right]) { + // 최소값은 mid 오른쪽 + left = mid + 1; + } else { + // 최소값은 mid 포함 왼쪽 + right = mid; + } + } + + return nums[left]; +}; diff --git a/maximum-depth-of-binary-tree/byol-han.js b/maximum-depth-of-binary-tree/byol-han.js new file mode 100644 index 000000000..e4ca2fa72 --- /dev/null +++ b/maximum-depth-of-binary-tree/byol-han.js @@ -0,0 +1,25 @@ +/** + * 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 {number} + */ +var maxDepth = function (root) { + // 트리가 비어있는 경우, 깊이는 0 + if (!root) return 0; + + // 왼쪽 서브트리의 최대 깊이를 재귀적으로 계산 + const leftDepth = maxDepth(root.left); + + // 오른쪽 서브트리의 최대 깊이를 재귀적으로 계산 + const rightDepth = maxDepth(root.right); + + // 왼쪽과 오른쪽 중 더 깊은 쪽을 선택하고, 현재 노드를 포함해 +1 + return Math.max(leftDepth, rightDepth) + 1; +}; diff --git a/merge-two-sorted-lists/byol-han.js b/merge-two-sorted-lists/byol-han.js new file mode 100644 index 000000000..f22883adb --- /dev/null +++ b/merge-two-sorted-lists/byol-han.js @@ -0,0 +1,42 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} list1 + * @param {ListNode} list2 + * @return {ListNode} + */ +var mergeTwoLists = function (list1, list2) { + // 가짜(head 역할을 할) 임시 노드 생성 + // 실제 결과 리스트는 dummy.next부터 시작됨 + let dummy = new ListNode(-1); + + // 현재 노드를 가리킬 포인터. 처음엔 dummy에서 시작 + let current = dummy; + + // 두 리스트 모두 null이 아닐 동안 반복 (비교 가능한 노드가 있을 때까지) + while (list1 !== null && list2 !== null) { + // list1의 현재 값이 더 작으면 list1 노드를 current.next에 붙임 + if (list1.val < list2.val) { + current.next = list1; // current 뒤에 list1 노드 연결 + list1 = list1.next; // list1 포인터를 다음 노드로 이동 + } else { + current.next = list2; // current 뒤에 list2 노드 연결 + list2 = list2.next; // list2 포인터를 다음 노드로 이동 + } + current = current.next; // current 포인터도 다음 노드로 이동 (리스트를 계속 이어가기 위해) + } + + // 위 반복문을 빠져나오면, 둘 중 하나는 null이 됨 + // 나머지 하나는 아직 정렬된 상태이므로 그대로 뒤에 붙여줌 + current.next = list1 !== null ? list1 : list2; + + // dummy는 첫 번째 노드를 가리키는 용도였으니, 실제 결과 리스트는 dummy.next부터 시작 + return dummy.next; +}; +// 시간 복잡도: O(n + m) (n: list1의 길이, m: list2의 길이) +// 공간 복잡도: O(1) (추가적인 공간 사용 없음) diff --git a/word-search/byol-han.js b/word-search/byol-han.js new file mode 100644 index 000000000..5d55f5023 --- /dev/null +++ b/word-search/byol-han.js @@ -0,0 +1,52 @@ +/** + * @param {character[][]} board + * @param {string} word + * @return {boolean} + */ +var exist = function (board, word) { + const rows = board.length; + const cols = board[0].length; + + function backtrack(row, col, index) { + // 종료 조건: 모든 글자를 찾았으면 true + if (index === word.length) return true; + + // 범위 밖이거나, 현재 칸 글자가 다르면 false + if ( + row < 0 || + row >= rows || + col < 0 || + col >= cols || + board[row][col] !== word[index] + ) { + return false; + } + + // 방문 처리 (임시로 다른 문자로 바꿔줌) + const temp = board[row][col]; + board[row][col] = "#"; + + // 상하좌우로 이동하면서 다음 글자 찾기 + const found = + backtrack(row + 1, col, index + 1) || // 아래 + backtrack(row - 1, col, index + 1) || // 위 + backtrack(row, col + 1, index + 1) || // 오른쪽 + backtrack(row, col - 1, index + 1); // 왼쪽 + + // 복구 (다시 원래 문자로 되돌리기) + board[row][col] = temp; + + return found; + } + + // board 전체 돌면서 시작점 찾기 + for (let row = 0; row < rows; row++) { + for (let col = 0; col < cols; col++) { + if (backtrack(row, col, 0)) { + return true; + } + } + } + + return false; +};