diff --git a/coin-change/JANGSEYEONG.js b/coin-change/JANGSEYEONG.js new file mode 100644 index 000000000..fe336234a --- /dev/null +++ b/coin-change/JANGSEYEONG.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} coins + * @param {number} amount + * @return {number} + */ +var coinChange = function (coins, amount) { + // f(n) = n을 만드는데 필요한 동전의 최소 개수 + // f(n) = min(f(n), f(n-coin) + 1) + + // dp 배열 초기화: 모든 금액을 만드는데 필요한 동전 개수를 불가능한 값(amount+1)으로 설정 + const dp = new Array(amount + 1).fill(amount + 1); + dp[0] = 0; // 0원은 0개의 동전으로 만들 수 있음 + coins.forEach((coin) => { + for (let i = coin; i < dp.length; i++) { + // dp[i]: 기존에 계산된 i원을 만드는 최소 동전 개수 + // dp[i-coin] + 1: (i-coin)원에 현재 동전 하나를 추가하여 i원을 만드는 경우 + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + }); + // 목표 금액을 만들 수 없으면 -1 반환, 가능하면 최소 동전 개수 반환 + return dp[amount] < amount + 1 ? dp[amount] : -1; +}; diff --git a/find-minimum-in-rotated-sorted-array/JANGSEYEONG.js b/find-minimum-in-rotated-sorted-array/JANGSEYEONG.js new file mode 100644 index 000000000..2e087eb07 --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/JANGSEYEONG.js @@ -0,0 +1,33 @@ +/*var findMin = function (nums) { + while (nums.length !== 1) { + if (nums[0] > nums[nums.length - 1]) { + // 앞에서 하나씩 자르기 + nums = nums.slice(1, nums.length); + } else { + return nums[0]; + } + } + return nums[0]; +};*/ +/** + * 위의 풀이처럼 풀면 최악의 경우 O(n)이 되어버림. 양 끝을 포인터로 가리키면서 이진탐색 + */ +/** + * @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]) { + left = mid + 1; + } else { + right = mid; + } + } + + return nums[left]; +}; diff --git a/maximum-depth-of-binary-tree/JANGSEYEONG.js b/maximum-depth-of-binary-tree/JANGSEYEONG.js new file mode 100644 index 000000000..1be409745 --- /dev/null +++ b/maximum-depth-of-binary-tree/JANGSEYEONG.js @@ -0,0 +1,31 @@ +/** + * 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) { + if (!root) return 0; // 노드가 없으면 깊이는 0 + + // 현재 노드가 존재하므로 기본 깊이는 1 + // 자식이 아예 없는 경우를 대비해 초기값 설정 + let left = 1; + let right = 1; + + // 왼쪽 서브트리가 있으면 재귀적으로 깊이 계산 후 현재 레벨(+1) 추가 + if (root.left) { + left = maxDepth(root.left) + 1; + } + // 오른쪽 서브트리가 있으면 재귀적으로 깊이 계산 후 현재 레벨(+1) 추가 + if (root.right) { + right = maxDepth(root.right) + 1; + } + // 왼쪽과 오른쪽 서브트리 중 더 깊은 값을 반환 + return Math.max(left, right); +}; diff --git a/merge-two-sorted-lists/JANGSEYEONG.js b/merge-two-sorted-lists/JANGSEYEONG.js new file mode 100644 index 000000000..a0a9f9823 --- /dev/null +++ b/merge-two-sorted-lists/JANGSEYEONG.js @@ -0,0 +1,34 @@ +/** + * 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) { + const answer = new ListNode(); + let temp = answer; // answer은 head를 가지고 있어야함 + + // list1, list2 중 하나라도 끝까지 도달할 때 까지 루프 돌리기 + while (list1 && list2) { + // 더 작은수를 가진 리스트를 연결 + if (list1.val < list2.val) { + temp.next = list1; + list1 = list1.next; + } else { + temp.next = list2; + list2 = list2.next; + } + temp = temp.next; + } + + // list1, list2 중 어떤게 끝까지 갔는지 몰라서 둘 다 체크 + // 남은건 그냥 뒤에 가져다가 붙이기 + temp.next = list1 || list2; + return answer.next; +}; diff --git a/word-search/JANGSEYEONG.js b/word-search/JANGSEYEONG.js new file mode 100644 index 000000000..43462e0dd --- /dev/null +++ b/word-search/JANGSEYEONG.js @@ -0,0 +1,50 @@ +/** + * @param {character[][]} board + * @param {string} word + * @return {boolean} + */ +// DFS 사용 이유: 한 경로를 끝까지 탐색해야 하고, 경로별로 독립적인 방문 상태가 필요하기 때문 +// BFS 불가 이유: 여러 경로를 동시에 탐색하면서 방문 상태가 섞여 올바른 경로를 놓칠 수 있음 +var exist = function (board, word) { + for (let y = 0; y < board.length; y++) { + for (let x = 0; x < board[0].length; x++) { + // 시작이 되는 단어를 마주치면 dfs 돌려보기 + if (board[y][x] === word[0] && dfs(board, y, x, word, 0)) { + return true; + } + } + } + return false; +}; + +function dfs(board, y, x, word, index) { + // 성공 조건: 모든 문자를 찾았을 때 + if (index === word.length) return true; + + // 실패 조건: 범위를 벗어나거나 현재 글자가 일치하지 않을 때 + if ( + y < 0 || + y >= board.length || + x < 0 || + x >= board[0].length || + board[y][x] !== word[index] + ) { + return false; + } + + // 현재 셀 사용 표시 + const temp = board[y][x]; + board[y][x] = true; // 임시 방문 표시 + + // 상하좌우 탐색, 하나라도 찾게된다면 true + const found = + dfs(board, y + 1, x, word, index + 1) || + dfs(board, y - 1, x, word, index + 1) || + dfs(board, y, x + 1, word, index + 1) || + dfs(board, y, x - 1, word, index + 1); + + // 원래 값으로 복원 (백트래킹) + board[y][x] = temp; + + return found; +}