diff --git a/combination-sum/Jeehay28.ts b/combination-sum/Jeehay28.ts new file mode 100644 index 000000000..9fd0b8471 --- /dev/null +++ b/combination-sum/Jeehay28.ts @@ -0,0 +1,82 @@ +// Approach 2: Dynamic Programming +// ✅ Time Complexity: O(N * T * K) +// ✅ Space Complexity: O(T * K) +// N = Number of candidates, T = target, K = average number of combination for each dp[i] + +function combinationSum(candidates: number[], target: number): number[][] { + // candidates = [2, 3] + // target = 5 + // dp = [ + // [[]], // dp[0] + // [], // dp[1] + // [[2]], // dp[2] + // [], // dp[3] + // [[2, 2]], // dp[4] + // [] // dp[5] + // ]; + + // dp = [ + // [[]], // dp[0] + // [], // dp[1] + // [[2]], // dp[2] + // [[3]], // dp[3] + // [[2, 2]], // dp[4] + // [[2, 3]] // dp[5] + // ]; + + const dp: number[][][] = Array.from({ length: target + 1 }, () => []); + // each element in dp is an independent array, and modifying one will not affect others. + dp[0] = [[]]; + + for (const candidate of candidates) { + for (let num = candidate; num <= target; num++) { + for (const combination of dp[num - candidate]) { + dp[num].push([...combination, candidate]); + } + } + } + + return dp[target]; +} + +// Approach 1: DFS + Backtracking (Recursive) +// ✅ Time Complexity: O(N^(T / min)) +// ✅ Space Complexity: O(K + target / min) +// If target = 7 and smallest number is 2, recursion can go up to 7 / 2 = levels deep +// N = number of candidates, T = target value, K = total number of valid combination found + +// function combinationSum(candidates: number[], target: number): number[][] { +// // input: +// // 1) an array of distinct integers +// // 2) a target integer + +// // output: +// // a list of all unique combinations of candinates where the chosen numbers sum to target(in any order) +// // duplicated numbers allowed + +// let result: number[][] = []; +// let nums: number[] = []; + +// const dfs = (start: number, total: number) => { +// if (total > target) { +// return; +// } + +// if (total === target) { +// result.push([...nums]); +// return; +// } + +// for (let i = start; i < candidates.length; i++) { +// if (total + nums[i] <= target) { +// nums.push(candidates[i]); +// dfs(i, total + candidates[i]); +// nums.pop(); // backtrack +// } +// } +// }; + +// dfs(0, 0); + +// return result; +// } diff --git a/decode-ways/Jeehay28.ts b/decode-ways/Jeehay28.ts new file mode 100644 index 000000000..06b369101 --- /dev/null +++ b/decode-ways/Jeehay28.ts @@ -0,0 +1,117 @@ +// Approach 4: +// Time Complexity: O(n) +// ✅ Space Complexity: O(1) + +function numDecodings(s: string): number { + // s: 2 2 6 + // dp: ? ? 1 + // cur nxt + + let next = 0, + current = 1; + + for (let start = s.length - 1; start >= 0; start--) { + const temp = current; + + if (s[start] === "0") { + // dp[start] = 0 + current = 0; + next = temp; + } else if ( + start + 1 < s.length && + parseInt(s.substring(start, start + 2)) < 27 + ) { + // dp[start] = dp[start + 1] + dp[start + 2] + current = current + next; + next = temp; + } else { + // dp[start] = dp[start + 1] + next = temp; + } + } + return current; +} + + +// Approach 3: Dynamic Programming +// Time Complexity: O(n) +// Space Complexity: O(n) + +// function numDecodings(s: string): number { +// // 12 +// // dp 001 +// // 211 + +// // 226 +// // dp 0001 +// // 3211 + +// const dp = Array.from({ length: s.length + 1 }, (el) => 0); +// dp[dp.length - 1] = 1; + +// for (let start = s.length - 1; start >= 0; start--) { +// if (s[start] === "0") { +// dp[start] = 0; +// } else if ( +// start + 1 < s.length && +// parseInt(s.substring(start, start + 2)) < 27 +// ) { +// dp[start] = dp[start + 1] + dp[start + 2]; +// } else { +// dp[start] = dp[start + 1]; +// } +// } + +// return dp[0]; +// } + + +// Approach 2 +// ✅ Time Complexity: O(2^n) -> O(n) +// Space Complexity: O(n) + +// function numDecodings(s: string): number { +// const memo = new Map(); +// memo.set(s.length, 1); + +// const dfs = (start: number) => { +// if (memo.has(start)) return memo.get(start); +// if (s[start] === "0") { +// memo.set(start, 0); +// } else if ( +// start + 1 < s.length && +// parseInt(s.substring(start, start + 2)) < 27 +// ) { +// memo.set(start, dfs(start + 1)! + dfs(start + 2)!); +// } else { +// memo.set(start, dfs(start + 1)!); +// } +// return memo.get(start); +// }; +// return dfs(0)!; +// } + + +// Approach 1 +// ❌ Time Limit Exceeded! +// Time Complexity: O(2^n), where n = s.length +// Space Compexity: O(n), due to recursive call stack +// function numDecodings(s: string): number { +// const dfs = (start: number) => { +// if (start === s.length) { +// return 1; +// } + +// if (s[start] === "0") { +// return 0; +// } + +// if (start + 1 < s.length && parseInt(s.substring(start, start + 2)) < 27) { +// return dfs(start + 1) + dfs(start + 2); +// } else { +// return dfs(start + 1); +// } +// }; + +// return dfs(0); +// } diff --git a/maximum-subarray/Jeehay28.ts b/maximum-subarray/Jeehay28.ts new file mode 100644 index 000000000..de5e7bd28 --- /dev/null +++ b/maximum-subarray/Jeehay28.ts @@ -0,0 +1,16 @@ +// Approach 1: +// Time Complexity: O(n) +// Space Complexity: O(1) + +function maxSubArray(nums: number[]): number { + let currentSum = nums[0]; + let maxSum = nums[0]; + + for (let i = 1; i < nums.length; i++) { + currentSum = Math.max(nums[i], currentSum + nums[i]); + maxSum = Math.max(currentSum, maxSum); + } + + return maxSum; +} + diff --git a/number-of-1-bits/Jeehay28.ts b/number-of-1-bits/Jeehay28.ts new file mode 100644 index 000000000..f8f5ef9fb --- /dev/null +++ b/number-of-1-bits/Jeehay28.ts @@ -0,0 +1,50 @@ +// Approach 2 +// 🗓️ 2025-04-15 +// ⏳ Time Complexity: O(log n) +// 💾 Space Complexity: O(1) + +function hammingWeight(n: number): number { + // n(이진수) & 1 -> 1: 이진수 n의 마지막 비트가 1인 경우에만 1 반환 + // n(이진수) >> 1: 마지막 비트 제거 + // 🔍 In binary numbers: + // Decimal: 11 + // Binary: 1 0 1 1 + // ↑ ↑ + // MSB LSB + // (Most Sig.) (Least Sig.) + // n & 1: only checks the least significant bit (LSB), if the LSB is 1, the result is 1. + // n >>= 1: Each bit is moved one place to the right. + + let count = 0; + + while (n) { + count += n & 1; // add 1 if the least significant bit of n is 1 + n >>= 1; // The LSB is removed (dropped). + } + + return count; +} + + +// Approach 1 +// 🗓️ 2025-04-15 +// ⏳ Time Complexity: O(log n) +// 💾 Space Complexity: O(1) + +// function hammingWeight(n: number): number { +// // input: a positive number n +// // output: the number of set bits in binary representation +// // set bits: a bit in the binary representaton of a number that has a value of 1 +// // 11 -> 1011 -> 3 + +// let cnt = 0; +// while (n > 0) { +// if (n % 2 === 1) { +// cnt += 1; +// } +// n = Math.floor(n / 2); +// } + +// return cnt; +// } + diff --git a/valid-palindrome/Jeehay28.ts b/valid-palindrome/Jeehay28.ts new file mode 100644 index 000000000..c6a9cc598 --- /dev/null +++ b/valid-palindrome/Jeehay28.ts @@ -0,0 +1,55 @@ +// Approach 2 +// 🗓️ 2025-04-14 +// ⏳ Time Complexity: O(n) +// 💾 Space Complexity: O(1) + +function isPalindrome(s: string): boolean { + let low = 0, high = s.length - 1; + const reg = /[0-9a-zA-Z]/; + + while (low < high) { + while (low < high && !reg.test(s[low])) { + low += 1; + } + + while (low < high && !reg.test(s[high])) { + high -= 1; + } + + if (s[low].toLowerCase() !== s[high].toLowerCase()) { + return false; + } + low += 1; + high -= 1; + } + + return true; +} + + +// Approach 1 +// 🗓️ 2025-04-14 +// ⏳ Time Complexity: O(n) +// 💾 Space Complexity: O(n) + +// function isPalindrome(s: string): boolean { +// // cover all uppercase letters into lowercasse letters +// // remove all non-alphanumeric characters (letters and numbers) +// // it reads the same forward and backward + +// const cleaned = s.toLowerCase().match(/[0-9a-z]/g); + +// // Converting to lowercase (toLowerCase()): O(n), where n is the length of the string +// // Matching with regex (match(/[0-9a-z]/g)): O(n), where n is the length of the string, as the regex engine needs to check each character in the string +// // join("") operation: O(m), where m is the length of the cleaned array. +// // reverse() operation: O(m), where m is the length of the cleaned array. +// // Comparison (s_forward === s_backward): O(n) because it checks each character one by one + +// if (cleaned !== null) { +// const s_forward = cleaned.join(""); +// const s_backward = cleaned.reverse().join(""); +// return s_forward === s_backward; +// } else { +// return true; +// } +// }