diff --git a/coin-change/Jeehay28.js b/coin-change/Jeehay28.js new file mode 100644 index 000000000..b80c66441 --- /dev/null +++ b/coin-change/Jeehay28.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} coins + * @param {number} amount + * @return {number} + */ + +// TC : O(c*a), where c is the number of coins, and a is amount +// SC : O(a) // dp array requires O(a) space + +var coinChange = function (coins, amount) { + // dynamic programming approach + + // dp[amount] : the minimum number of coins + // as a default, dp[0] = 0, for other amounts, dp[amount] = amount + 1 () + // [0, amount+1, amount+1, ...] + const dp = [0, ...new Array(amount).fill(amount + 1)]; + + // start from coin because i - coin >= 0 + for (const coin of coins) { + for (let i = coin; i <= amount; i++) { + // dp[i] : not using the current coin + // dp[i - coin] + 1 : using the current coin + dp[i] = Math.min(dp[i - coin] + 1, dp[i]); + } + } + + // dp[amount] === amount + 1 : that amount of money cannot be made up by any combination of the coins + return dp[amount] < amount + 1 ? dp[amount] : -1; +}; + + diff --git a/merge-two-sorted-lists/Jeehay28.js b/merge-two-sorted-lists/Jeehay28.js new file mode 100644 index 000000000..cb331161f --- /dev/null +++ b/merge-two-sorted-lists/Jeehay28.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} + */ + +// Time Complexity: O(m + n) +// Space Complexity: O(m + n) + +var mergeTwoLists = function(list1, list2) { + + + if(!(list1 && list2)) { + return list1 || list2; + } + + if(list1.val < list2.val) { + list1.next = mergeTwoLists(list1.next, list2); + return list1; + } else { + list2.next = mergeTwoLists(list1, list2.next); + return list2; + } + +}; + + diff --git a/missing-number/Jeehay28.js b/missing-number/Jeehay28.js new file mode 100644 index 000000000..a47a59fe7 --- /dev/null +++ b/missing-number/Jeehay28.js @@ -0,0 +1,68 @@ +/** + * @param {number[]} nums + * @return {number} + */ + +// *** Guided approach 2: bitwise operations and avoids potential overflow issues with very large sums +// XOR method +// Time complexity: O(n)(two loops: one for numbers 0 to n and one for array elements) +// Space complexity: O(1) + +var missingNumber = function (nums) { + // XOR with itself results in 0 : a xor a = 0 + // XOR with 0 results in the number itself : a xor 0 = a + // XOR is commutative and associative + + const n = nums.length; + + let xor = 0; + + for (let i = 0; i <= n; i++) { + xor ^= i; + } + + for (any of nums) { + xor ^= any; + } + + return xor; +}; + +// *** Guided approach 1: simplicity and clarity +// Gauss' Formula (Sum of First n Numbers): n*(n+1) / 2 +// Time complexity: O(n) +// Space complexity: O(1) +// var missingNumber = function (nums) { +// const n = nums.length; +// const expectedSum = (n * (n + 1)) / 2; +// const actualSum = nums.reduce((acc, cur) => acc + cur, 0); // O(n) + +// const missingNum = expectedSum - actualSum; + +// return missingNum; +// }; + +// *** My own approach +// Time complexity: O(n^2) +// Space complexity: O(n) +// var missingNumber = function (nums) { + +// let distinctNums = new Set([]); + +// for (any of nums) { +// if (distinctNums.has(any)) { +// return +// } else { +// distinctNums.add(any) +// } +// } + +// const n = distinctNums.size; + +// for (let i = 0; i <= n; i++) { +// if (!nums.includes(i)) { +// return i; +// } +// } + +// }; diff --git a/palindromic-substrings/Jeehay28.js b/palindromic-substrings/Jeehay28.js new file mode 100644 index 000000000..a28fb5d0c --- /dev/null +++ b/palindromic-substrings/Jeehay28.js @@ -0,0 +1,37 @@ +/** + * @param {string} s + * @return {number} + */ + +// TC : O(n^2) +// SC : O(1) + +var countSubstrings = function (s) { + // For each character in the string, treat it as the center of a potential palindrome. + + // 'Count Palindromic Substrings' helper function + const countPS = (left, right) => { + let cnt = 0; + while (left >= 0 && right < s.length && s[left] === s[right]) { + cnt += 1; + left -= 1; + right += 1; + } + return cnt; + }; + + let totCnt = 0; + + for (let i = 0; i < s.length; i++) { + // left === right : 1 center point, odd-length palindromic + totCnt += countPS(i, i); + + // left !== right : 2 center points, even-length palindromic + totCnt += countPS(i, i + 1); + } + + return totCnt; +}; + + + diff --git a/word-search/Jeehay28.js b/word-search/Jeehay28.js new file mode 100644 index 000000000..bdbe2bc97 --- /dev/null +++ b/word-search/Jeehay28.js @@ -0,0 +1,67 @@ +/** + * @param {character[][]} board + * @param {string} word + * @return {boolean} + */ + +// board(N * M), where N is the number of row and M is the number of columns +// L, the length of the word +// TC : O(N * M * 4^L) + +// recursion depth : the length of the word (L) +// each recursion call requires constant space. +// SC : O(L) + +var exist = function (board, word) { + let row = board.length; + let col = board[0].length; + + const dfs = (r, c, idx) => { + // search done + if (idx === word.length) { + return true; + } + + // row and column are out of range + if (r < 0 || r >= row || c < 0 || c >= col) { + return false; + } + + if (board[r][c] !== word[idx]) { + return false; + } + + // word[idx] === board[r][c] + // continue searching for word[idx + 1] in adjacent cells on the board + const temp = board[r][c]; + board[r][c] = "visited"; + + const arr = [ + [1, 0], // Move down + [-1, 0], // Move up + [0, 1], // Move right + [0, -1], // Move left + ]; + for (const [up, right] of arr) { + if (dfs(r + up, c + right, idx + 1)) { + return true; + } + } + + board[r][c] = temp; + return false; + }; + + for (let i = 0; i < row; i++) { + for (let j = 0; j < col; j++) { + if (dfs(i, j, 0)) { + return true; + } + } + } + + return false; +}; + + +