diff --git a/coin-change/Jeehay28.ts b/coin-change/Jeehay28.ts new file mode 100644 index 000000000..d7a7bbeee --- /dev/null +++ b/coin-change/Jeehay28.ts @@ -0,0 +1,72 @@ +// Approach 2: Dynamic Programming +// // Time Complexity: O(amout * n), where n is the number of coins +// // Space Complexity: O(amount) + +function coinChange(coins: number[], amount: number): number { + + // input: coins = [2, 3, 5], amount = 7 + + // initial state dp + // 0: 0 + // 1: amount + 1 = 8 + // 2: 8 + // 3: 8 + // 4: 8 + // 5: 8 + // 6: 8 + // 7: 8 + + // using coin 2 + // 0: 0 + // 1: 8 + // 2: 8 -> 8 vs dp[2-2] + 1 = 1 -> 1 + // 3: 8 -> 8 vs dp[3-2] + 1 = 9 -> 8 + // 4: 8 -> 8 vs dp[4-2] + 1 = 2 -> 2 + // 5: 8 -> 8 vs dp[5-2] + 1 = 9 -> 8 + // 6: 8 -> 8 vs dp[6-2] + 1 = 3 -> 3 + // 7: 8 -> 8 vs dp[7-2] + 1 = 9 -> 8 + + const dp = Array.from({ length: amount + 1 }, () => amount + 1); + dp[0] = 0 + + for (const coin of coins) { + for (let currentTotal = coin; currentTotal <= amount; currentTotal++) { + dp[currentTotal] = Math.min(dp[currentTotal - coin] + 1, dp[currentTotal]) + } + } + + return dp[amount] > amount ? -1 : dp[amount] +}; + + +// // Approach 1: BFS Traversal +// // Time Complexity: O(amout * n), where n is the number of coins +// // Space Complexity: O(amount) + +// function coinChange(coins: number[], amount: number): number { +// // queue: [[number of coints, current total]] +// let queue = [[0, 0]]; +// let visited = new Set(); + +// while (queue.length > 0) { +// const [cnt, total] = queue.shift()!; + +// if (total === amount) { +// return cnt; +// } + +// if (visited.has(total)) { +// continue; +// } +// visited.add(total); + +// for (const coin of coins) { +// if (total + coin <= amount) { +// queue.push([cnt + 1, total + coin]); +// } +// } +// } + +// return -1; +// } + diff --git a/find-minimum-in-rotated-sorted-array/Jeehay28.ts b/find-minimum-in-rotated-sorted-array/Jeehay28.ts new file mode 100644 index 000000000..dd65eadac --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/Jeehay28.ts @@ -0,0 +1,48 @@ +// Approach 2: binary search +// Time Complexity: ✅ O(log n) +// Space Complexity: O(1) + +function findMin(nums: number[]): number { + + let left = 0 + let right = nums.length - 1 + + while(left < right) { + + const mid = Math.floor((left + right) / 2) + + if(nums[mid] > nums[right]) { + // the min must be to the right of mid + left = mid + 1 + } else { + // the mins could be mid or to the left + right = mid + } + } + + return nums[left] +}; + + +// Approach 1: +// Time Complexity: ❌ O(n) +// Space Complexity: O(1) + +// function findMin(nums: number[]): number { +// // input: an array of length n sorted in ascending order +// // rotate: a[n-1], a[0], ..., a[n-2] +// // time complexity allowed: O(log n) + +// let first = nums[0]; +// let last = nums[nums.length - 1]; +// let cnt = 0; + +// while (first > last) { +// first = last; +// cnt += 1; +// last = nums[nums.length - 1 - cnt]; +// } + +// return first; +// } + diff --git a/maximum-depth-of-binary-tree/Jeehay28.ts b/maximum-depth-of-binary-tree/Jeehay28.ts new file mode 100644 index 000000000..b0579943b --- /dev/null +++ b/maximum-depth-of-binary-tree/Jeehay28.ts @@ -0,0 +1,75 @@ +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; + } +} + +// Approach 3: +// Time Complexity: O(n) +// Space Complexity: O(n), due to the recursion stack + +function maxDepth(root: TreeNode | null): number { + if (!root) return 0; + + return 1 + Math.max(maxDepth(root.left), maxDepth(root.right)); +} + +// Approach 2: +// Time Complexity: O(n) +// Space Complexity: O(n) + +// function maxDepth(root: TreeNode | null): number { +// if (!root) return 0; + +// let maxDepth = 0; +// let stack: Array<[TreeNode, number]> = [[root, 1]]; + +// while (stack.length > 0) { +// const item = stack.pop(); + +// if (!item) continue; + +// const [node, depth] = item; + +// maxDepth = Math.max(maxDepth, depth); + +// if (node.left) { +// stack.push([node.left, depth + 1]); +// } + +// if (node.right) { +// stack.push([node.right, depth + 1]); +// } +// } + +// return maxDepth; +// } + + +// Approach 1 +// Time Compleixty:O(n) +// Space Complexity:O(n), due to the recursion stack + +// function maxDepth(root: TreeNode | null): number { +// let maxCnt = 0; + +// const dfs = (node: TreeNode | null, cnt: number) => { +// if (!node) { +// maxCnt = Math.max(maxCnt, cnt); +// return; +// } + +// dfs(node.left, cnt + 1); +// dfs(node.right, cnt + 1); +// }; + +// dfs(root, 0); + +// return maxCnt; +// } + diff --git a/merge-two-sorted-lists/Jeehay28.ts b/merge-two-sorted-lists/Jeehay28.ts new file mode 100644 index 000000000..ba16cd805 --- /dev/null +++ b/merge-two-sorted-lists/Jeehay28.ts @@ -0,0 +1,82 @@ +// Approach 2: +// ✅ Time Complexity: O(n) +// ✅ Space Complexity: O(1) + +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; + } +} + +function mergeTwoLists( + list1: ListNode | null, + list2: ListNode | null +): ListNode | null { + let dummy = new ListNode(0); + let current = dummy; + + 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; // Attach whatever is left + + return dummy.next; +} + + +// Approach 1: works, but not efficient for big inputs +// Time Complexity: O(n log n) +// Space Complexity: O(n) + +// function mergeTwoLists( +// list1: ListNode | null, +// list2: ListNode | null +// ): ListNode | null { +// let stack: number[] = []; + +// const dfs = (node: ListNode | null) => { +// if (!node) { +// return; +// } + +// stack.push(node.val); + +// return dfs(node.next); +// }; + +// dfs(list1); +// dfs(list2); + +// stack.sort((a, b) => a - b); + +// if (stack.length === 0) { +// return null; +// } + +// let merged = new ListNode(); +// let dummy = merged; + +// for (let i = 0; i < stack.length; i++) { +// dummy.val = stack[i]; + +// if (i !== stack.length - 1) { +// dummy.next = new ListNode(); +// dummy = dummy.next; +// } else { +// dummy.next = null; +// } +// } + +// return merged; +// } diff --git a/word-search/Jeehay28.ts b/word-search/Jeehay28.ts new file mode 100644 index 000000000..93eb112d7 --- /dev/null +++ b/word-search/Jeehay28.ts @@ -0,0 +1,46 @@ +// Time Complexity: O(m * n * 4^L), where L is the length of the word +// Space Complexity: O(L) due to he recursive call stack + +function exist(board: string[][], word: string): boolean { + // input: m * n grid of characters board, a string word + // output: true if word exists in the grid + + const dfs = (index: number, row: number, col: number) => { + if ( + row < 0 || + row >= board.length || + col < 0 || + col >= board[0].length || + board[row][col] !== word[index] + ) { + return false; + } + + if (index === word.length - 1) { + return true; + } + + const visited = board[row][col]; + board[row][col] = "#"; + + const result = + dfs(index + 1, row + 1, col) || + dfs(index + 1, row - 1, col) || + dfs(index + 1, row, col + 1) || + dfs(index + 1, row, col - 1); + + board[row][col] = visited; + + return result; + }; + + for (let i = 0; i < board.length; i++) { + for (let j = 0; j < board[0].length; j++) { + if (dfs(0, i, j)) { + return true; + } + } + } + + return false; +}