diff --git a/coin-change/Blossssom.ts b/coin-change/Blossssom.ts new file mode 100644 index 0000000000..b571554370 --- /dev/null +++ b/coin-change/Blossssom.ts @@ -0,0 +1,29 @@ +/** + * @param coins - 동전 종류 배열 + * @param amount - 총 금액 + * @returns - 총 사용 코인 갯수 + * @description + * - 탐욕으로 풀면 최소 동전갯수를 구할 수 없음 + * - dp 로 풀이 + * - 1 부터 금액의 코인 사용 갯수를 추가해 가며, 이전에 구해놓은 값과 min 비교 + */ +function coinChange(coins: number[], amount: number): number { + const dp = new Array(amount + 1).fill(Infinity); + + dp[0] = 0; + + for (let i = 1; i <= amount; i++) { + for (const coin of coins) { + if (i - coin >= 0) { + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + } + + return dp[amount] === Infinity ? -1 : dp[amount]; +} + +const coins = [1, 2, 5]; +const amount = 11; +coinChange(coins, amount); + diff --git a/find-minimum-in-rotated-sorted-array/Blossssom.ts b/find-minimum-in-rotated-sorted-array/Blossssom.ts new file mode 100644 index 0000000000..1264f28213 --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/Blossssom.ts @@ -0,0 +1,32 @@ +/** + * @param nums - 오름차순 정렬된 정수 배열 + * @returns - 최솟값 + * @description + * - 이진 탐색으로 right와 비교하며 배열의 범위를 좁혀가며 탐색 + * - left와 right가 겹치는 포인트가 최솟값 + */ + +function findMin(nums: number[]): number { + let left = 0; + let mid = Math.floor(nums.length / 2); + let right = nums.length - 1; + + if (nums.length < 2) { + return nums[0]; + } + + while (left < right) { + if (nums[right] < nums[mid]) { + left = mid + 1; + } else { + right = mid; + } + + mid = Math.floor((left + right) / 2); + } + return nums[left]; +} + +const nums = [2, 1]; +console.log(findMin(nums)); + diff --git a/maximum-depth-of-binary-tree/Blossssom.ts b/maximum-depth-of-binary-tree/Blossssom.ts new file mode 100644 index 0000000000..9a512979e2 --- /dev/null +++ b/maximum-depth-of-binary-tree/Blossssom.ts @@ -0,0 +1,53 @@ +class TreeNode { + val: number; + left: TreeNode | null; + right: TreeNode | null; + constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { + this.val = val === undefined ? 0 : val; + this.left = left === undefined ? null : left; + this.right = right === undefined ? null : right; + } +} + +/** + * @param root - 이진 트리 + * @returns - 루트 노드에서 가장 먼 리프노드 까지 가장 긴 경로를 따른 노드 수 + * @description + * - root가 없는 경우를 제외 후 재귀 호출로 1씩 증가 + * - left, right 중 가장 큰 값을 return + * - maxDepth 자체를 재귀로 사용하는 방식이 가장 효율적 + */ + +// function maxDepth(root: TreeNode | null): number { +// if (!root) { +// return 0; +// } + +// function recursive(current: TreeNode | null): number { +// if (!current) { +// return 0; +// } + +// return 1 + Math.max(recursive(current.left), recursive(current.right)); +// } + +// return recursive(root); +// } + +function maxDepth(root: TreeNode | null): number { + if (root === null) { + return 0; + } + + const left = 1 + maxDepth(root.left); + const right = 1 + maxDepth(root.right); + + return Math.max(left, right); +} + +const root = new TreeNode( + 3, + new TreeNode(9), + new TreeNode(20, new TreeNode(15), new TreeNode(7)) +); + diff --git a/merge-two-sorted-lists/Blossssom.ts b/merge-two-sorted-lists/Blossssom.ts new file mode 100644 index 0000000000..68eb338982 --- /dev/null +++ b/merge-two-sorted-lists/Blossssom.ts @@ -0,0 +1,49 @@ +class ListNode { + val: number; + next: ListNode | null; + constructor(val?: number, next?: ListNode | null) { + this.val = val === undefined ? 0 : val; + this.next = next === undefined ? null : next; + } +} + +/** + * @param linked_list list1 + * @param linked_list list2 + * @returns 정렬된 linked_list + * @description + * - 연결리스트로 각 단계를 탐색하려니 접근 방법이 떠오르지 않음 + * - 해당 유형의 문제를 더 풀어볼 예정 + */ + +function mergeTwoLists( + list1: ListNode | null, + list2: ListNode | null +): ListNode | null { + if (!list1 && !list2) { + return null; + } + + const temp = new ListNode(); + let current = temp; + + while (list1 && list2) { + if (list1.val < list2.val) { + current.next = list1; + list1 = list1.next; + } else { + current.next = list2; + list2 = list2.next; + } + current = current.next; + } + current.next = list1 || list2; + + return temp.next; +} + +const list1 = new ListNode(1, new ListNode(2, new ListNode(4))); +const list2 = new ListNode(1, new ListNode(3, new ListNode(4))); + +mergeTwoLists(list1, list2); + diff --git a/word-search/Blossssom.ts b/word-search/Blossssom.ts new file mode 100644 index 0000000000..f0e5046ae8 --- /dev/null +++ b/word-search/Blossssom.ts @@ -0,0 +1,73 @@ +/** + * @param board - m * n 문자 그리드 + * @param word - 찾을 단어 + * @returns - 그리드 내 인접한 셀의 글자로 word를 만들 수 있는지 반환 + * @description + * - 동일한 셀 글자는 한 번만 사용가능 + * - visit 체크 부분에서 조금 생각을 잘못해 오래걸림 + * - dfs 연습 필요, 문제를 최대한 잘게 잘라서 생각해보기 + */ + +function exist(board: string[][], word: string): boolean { + const maximumRow = board.length - 1; + const maximumCol = board[0].length - 1; + // 시작지점 찾기 + const starter = board.reduce((acc, row, rIndex) => { + row.forEach((col, cIndex) => { + if (col === word[0]) { + acc.push([rIndex, cIndex]); + } + }); + return acc; + }, []); + + function recursive(row: number, col: number, target: number): boolean { + // word의 길이까지 왔다면 이전 조건은 통과 즉, word와 동일 문자열 + if (target === word.length) { + return true; + } + + // 인접 index 범위 체크 및 값 체크 + if ( + row < 0 || + row > maximumRow || + col < 0 || + col > maximumCol || + board[row][col] !== word[target] + ) { + return false; + } + // 이전 값을 동일 체크하지 않도록 값을 저장 및 변경 + const saveValue = board[row][col]; + // 찡긋 + board[row][col] = ">_o"; + + const finding = + recursive(row + 1, col, target + 1) || + recursive(row - 1, col, target + 1) || + recursive(row, col + 1, target + 1) || + recursive(row, col - 1, target + 1); + + // 다음 순회 및 체크를 위한 원상복구 + board[row][col] = saveValue; + return finding; + } + + for (const start of starter) { + const isFind = recursive(start[0], start[1], 0); + if (isFind) { + return true; + } + } + return false; +} + +const board = [ + ["A", "B", "C", "E"], + ["S", "F", "C", "S"], + ["A", "D", "E", "E"], +]; + +const word = "ABCCED"; +console.log(exist(board, word)); +