diff --git a/typescript/100-Same-Tree.ts b/typescript/100-Same-Tree.ts new file mode 100644 index 000000000..0599ed4ff --- /dev/null +++ b/typescript/100-Same-Tree.ts @@ -0,0 +1,28 @@ +/** + * Definition for a binary tree node. + * 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) + * } + * } + */ + +function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean { + if (p === null && q === null) return true; + + if ((p === null && q !== null) || (p !== null && q === null)) return false; + + let leftSame = isSameTree(p.left, q.left); + let rightSame = isSameTree(p.right, q.right); + + if (p.val === q.val && leftSame && rightSame) { + return true; + } + + return false; +} diff --git a/typescript/102-Binary-Tree-Level-Order-Traversal.ts b/typescript/102-Binary-Tree-Level-Order-Traversal.ts new file mode 100644 index 000000000..48b477ac2 --- /dev/null +++ b/typescript/102-Binary-Tree-Level-Order-Traversal.ts @@ -0,0 +1,36 @@ +/** + * Definition for a binary tree node. + * 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) + * } + * } + */ + +function levelOrder(root: TreeNode | null): number[][] { + const levels: number[][] = []; + + function getHeight(node: TreeNode | null, height: number) { + if (!node) return 0; + + if (node.left || node.right) { + getHeight(node.left, height + 1); + getHeight(node.right, height + 1); + } + + if (levels[height]) { + levels[height].push(node.val); + } else { + levels[height] = [node.val]; + } + } + + getHeight(root, 0); + + return levels; +} diff --git a/typescript/104-Maximum-Depth-of-Binary-Tree.ts b/typescript/104-Maximum-Depth-of-Binary-Tree.ts new file mode 100644 index 000000000..949af17d6 --- /dev/null +++ b/typescript/104-Maximum-Depth-of-Binary-Tree.ts @@ -0,0 +1,19 @@ +/** + * Definition for a binary tree node. + * 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) + * } + * } + */ + +function maxDepth(root: TreeNode | null): number { + if (!root) return 0; + + return 1 + Math.max(maxDepth(root.left), maxDepth(root.right)); +} diff --git a/typescript/11-Container-With-Most-Water.ts b/typescript/11-Container-With-Most-Water.ts new file mode 100644 index 000000000..59a4dac59 --- /dev/null +++ b/typescript/11-Container-With-Most-Water.ts @@ -0,0 +1,19 @@ +function maxArea(height: number[]): number { + let l = 0; + let r = height.length - 1; + let max = 0; + + while (l < r) { + let area = (r - l) * Math.min(height[l], height[r]); + + max = Math.max(max, area); + + if (height[l] < height[r]) { + l += 1; + } else { + r -= 1; + } + } + + return max; +} diff --git a/typescript/110-Balanced-Binary-Tree.ts b/typescript/110-Balanced-Binary-Tree.ts new file mode 100644 index 000000000..baa990c19 --- /dev/null +++ b/typescript/110-Balanced-Binary-Tree.ts @@ -0,0 +1,29 @@ +/** + * Definition for a binary tree node. + * 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) + * } + * } + */ + +function isBalanced(root: TreeNode | null): boolean { + let array = getHeight(root); + return array[0]; +} + +function getHeight(root: TreeNode | null) { + if (!root) return [true, 0]; + + let [leftBalanced, leftHeight] = getHeight(root.left); + let [rightBalanced, rightHeight] = getHeight(root.right); + + let balanced = leftBalanced && rightBalanced && Math.abs(rightHeight - leftHeight) <= 1; + + return [balanced, 1 + Math.max(leftHeight, rightHeight)]; +} diff --git a/typescript/121-Best-Time-To-Buy-and-Sell-Stock.ts b/typescript/121-Best-Time-To-Buy-and-Sell-Stock.ts new file mode 100644 index 000000000..aa05c61d4 --- /dev/null +++ b/typescript/121-Best-Time-To-Buy-and-Sell-Stock.ts @@ -0,0 +1,19 @@ +function maxProfit(prices: number[]): number { + let max = 0; + let l = 0; + let r = 1; + + while (r < prices.length) { + if (prices[l] < prices[r]) { + let profit = prices[r] - prices[l]; + if (profit > max) { + max = profit; + } + } else { + l = r; + } + r++; + } + + return max; +} diff --git a/typescript/125-Valid-Palindrome.ts b/typescript/125-Valid-Palindrome.ts new file mode 100644 index 000000000..a1f7736ce --- /dev/null +++ b/typescript/125-Valid-Palindrome.ts @@ -0,0 +1,13 @@ +function isPalindrome(s: string): boolean { + const array = s.toLowerCase().replace(/[^A-Za-z0-9]/g, "").replace(/\s/g, "").split(""); + + for (let i = 0; i < array.length; i++) { + const first = array[i]; + const second = array[array.length - 1 - i]; + + if (first !== second) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/typescript/128-Longest-Consecutive-Sequence.ts b/typescript/128-Longest-Consecutive-Sequence.ts new file mode 100644 index 000000000..74b437aa5 --- /dev/null +++ b/typescript/128-Longest-Consecutive-Sequence.ts @@ -0,0 +1,16 @@ +function longestConsecutive(nums: number[]): number { + const number = new Set(nums); + let longest = 0; + + for (const n of nums) { + if (!number.has(n - 1)) { + let length = 0; + while (number.has(n + length)) { + length += 1; + } + longest = Math.max(length, longest); + } + } + + return longest; +} diff --git a/typescript/131-Palindrome-Partitioning.ts b/typescript/131-Palindrome-Partitioning.ts new file mode 100644 index 000000000..134b4c19b --- /dev/null +++ b/typescript/131-Palindrome-Partitioning.ts @@ -0,0 +1,33 @@ +function partition(s: string): string[][] { + let res: string[][] = []; + let part: string[] = []; + + function dfs(i: number) { + if (i >= s.length) { + res.push(part.slice()); + return; + } + + for (let j = i; j < s.length; j++) { + if (isPali(s, i, j)) { + part.push(s.slice(i, j + 1)); + dfs(j + 1); + part.pop(); + } + } + } + + dfs(0); + return res; + + function isPali(s: string, l: number, r: number) { + while (l < r) { + if (s[l] != s[r]) { + return false; + } + l = l + 1; + r = r - 1; + } + return true; + } +} diff --git a/typescript/136-Single-Number.ts b/typescript/136-Single-Number.ts new file mode 100644 index 000000000..a87e7cf05 --- /dev/null +++ b/typescript/136-Single-Number.ts @@ -0,0 +1,9 @@ +function singleNumber(nums: number[]): number { + let res = 0; + + for (let i = 0; i < nums.length; i++) { + res = nums[i] ^ res; + } + + return res; +} diff --git a/typescript/139-Word-Break.ts b/typescript/139-Word-Break.ts new file mode 100644 index 000000000..c20ad3ba0 --- /dev/null +++ b/typescript/139-Word-Break.ts @@ -0,0 +1,18 @@ +function wordBreak(s: string, wordDict: string[]): boolean { + const dp = Array(s.length + 1).fill(false); + + dp[s.length] = true; + + for (let i = s.length - 1; i > -1; i--) { + for (const w of wordDict) { + if (i + w.length <= s.length && s.slice(i, i + w.length) == w) { + dp[i] = dp[i + w.length]; + } + if (dp[i]) { + break; + } + } + } + + return dp[0]; +} diff --git a/typescript/141-Linked-List-Cycle.ts b/typescript/141-Linked-List-Cycle.ts new file mode 100644 index 000000000..48990f3e6 --- /dev/null +++ b/typescript/141-Linked-List-Cycle.ts @@ -0,0 +1,28 @@ +/** + * Definition for singly-linked list. + * 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 hasCycle(head: ListNode | null): boolean { + let slow = head; + let fast = head; + + while (fast && fast.next) { + if (slow) { + slow = slow.next; + } + fast = fast.next.next; + if (slow == fast) { + return true; + } + } + + return false; +} diff --git a/typescript/143-Reorder-List.ts b/typescript/143-Reorder-List.ts new file mode 100644 index 000000000..549c807cf --- /dev/null +++ b/typescript/143-Reorder-List.ts @@ -0,0 +1,48 @@ +/** + * Definition for singly-linked list. + * 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) + * } + * } + */ + +/** + Do not return anything, modify head in-place instead. + */ +function reorderList(head: ListNode | null): void { + let slow: ListNode | null | undefined = head; + let fast: ListNode | null | undefined = head?.next; + + while (fast && fast.next) { + slow = slow?.next; + fast = fast?.next?.next; + } + + // reverse second half + if (!(slow && slow.next)) return; + let second: ListNode | null = slow.next; + slow.next = null; + let prev: ListNode | null = null; + while (second) { + let temp = second.next; + second.next = prev; + prev = second; + second = temp; + } + + // merge two halfs + let first: any = head; + second = prev; + while (second) { + let temp1 = first.next; + let temp2 = second.next; + first.next = second; + second.next = temp1; + first = temp1; + second = temp2; + } +} diff --git a/typescript/15-3Sum.ts b/typescript/15-3Sum.ts new file mode 100644 index 000000000..eee406ca8 --- /dev/null +++ b/typescript/15-3Sum.ts @@ -0,0 +1,29 @@ +function threeSum(nums: number[]): number[][] { + const res: number[][] = []; + nums = nums.sort((a, b) => a - b); + + for (let i = 0; i < nums.length; i++) { + if (i > 0 && nums[i] == nums[i - 1]) { + continue; + } + + let l = i + 1; + let r = nums.length - 1; + while (l < r) { + let sum = nums[i] + nums[l] + nums[r]; + + if (sum > 0) { + r -= 1; + } else if (sum < 0) { + l += 1; + } else { + res.push([nums[i], nums[l], nums[r]]); + l += 1; + while (nums[l] == nums[l - 1] && l < r) { + l += 1; + } + } + } + } + return res; +} diff --git a/typescript/150-Evaluate-Reverse-Polish-Notation.ts b/typescript/150-Evaluate-Reverse-Polish-Notation.ts new file mode 100644 index 000000000..166ff2304 --- /dev/null +++ b/typescript/150-Evaluate-Reverse-Polish-Notation.ts @@ -0,0 +1,23 @@ +function evalRPN(tokens: string[]): number { + const stack: number[] = []; + + tokens.forEach((token) => { + if (token === "+") { + stack.push(Number(stack.pop()) + Number(stack.pop())); + } else if (token === "-") { + const a = Number(stack.pop()); + const b = Number(stack.pop()); + stack.push(b - a); + } else if (token === "/") { + const a = Number(stack.pop()); + const b = Number(stack.pop()); + stack.push(Math.trunc(b / a)); + } else if (token === "*") { + stack.push(Number(stack.pop()) * Number(stack.pop())); + } else { + stack.push(Number(token)); + } + }); + + return stack[0]; +} diff --git a/typescript/152-Maximum-Product-Subarray.ts b/typescript/152-Maximum-Product-Subarray.ts new file mode 100644 index 000000000..4f1fef063 --- /dev/null +++ b/typescript/152-Maximum-Product-Subarray.ts @@ -0,0 +1,20 @@ +function maxProduct(nums: number[]): number { + let res = Math.max(...nums); + let curMax = 1; + let curMin = 1; + + for (const n of nums) { + if (n === 0) { + curMin = 1; + curMax = 1; + continue; + } + + let temp = curMax * n; + curMax = Math.max(n * curMax, n * curMin, n); + curMin = Math.min(temp, n * curMin, n); + res = Math.max(res, curMax); + } + + return res; +} diff --git a/typescript/155-Min-Stack.ts b/typescript/155-Min-Stack.ts new file mode 100644 index 000000000..d15f46cfb --- /dev/null +++ b/typescript/155-Min-Stack.ts @@ -0,0 +1,52 @@ +class MinStack { + stack: number[]; + minstack: number[]; + + constructor() { + this.stack = []; + this.minstack = []; + } + + push(val: number): void { + this.stack.push(val); + if ( + val < this.minstack[this.minstack.length - 1] || + this.minstack.length === 0 + ) { + this.minstack.push(val); + } else { + this.minstack.push(this.minstack[this.minstack.length - 1]); + } + } + + pop(): void { + this.stack.pop(); + this.minstack.pop(); + } + + top(): number { + return this.stack[this.stack.length - 1]; + } + + getMin(): number { + return this.minstack[this.minstack.length - 1]; + } +} + +/** + * Your MinStack object will be instantiated and called as such: + * var obj = new MinStack() + * obj.push(val) + * obj.pop() + * var param_3 = obj.top() + * var param_4 = obj.getMin() + */ + +const minStack = new MinStack(); +minStack.push(-2); +minStack.push(0); +minStack.push(-3); +minStack.getMin(); +minStack.pop(); +minStack.top(); +minStack.getMin(); diff --git a/typescript/167-Two-Sum-II.ts b/typescript/167-Two-Sum-II.ts new file mode 100644 index 000000000..2d8c23590 --- /dev/null +++ b/typescript/167-Two-Sum-II.ts @@ -0,0 +1,14 @@ +function twoSum(numbers: number[], target: number): number[] { + let L = 0; + let R = numbers.length - 1; + + while (numbers[L] + numbers[R] !== target) { + if (numbers[L] + numbers[R] > target) { + R = R - 1; + } else if (numbers[L] + numbers[R] < target) { + L = L + 1; + } + } + + return [L + 1, R + 1]; +} diff --git a/typescript/17-Letter-Combinations-of-a-Phone-Number.ts b/typescript/17-Letter-Combinations-of-a-Phone-Number.ts new file mode 100644 index 000000000..cd347efc5 --- /dev/null +++ b/typescript/17-Letter-Combinations-of-a-Phone-Number.ts @@ -0,0 +1,31 @@ +function letterCombinations(digits: string): string[] { + let res: string[] = []; + + const digitToChar = { + "2": "abc", + "3": "def", + "4": "ghi", + "5": "jkl", + "6": "mno", + "7": "qprs", + "8": "tuv", + "9": "wxyz", + }; + + function backtrack(i: number, curStr: string) { + if (curStr.length === digits.length) { + res.push(curStr); + return; + } + + for (const c of digitToChar[digits[i]]) { + backtrack(i + 1, curStr + c); + } + } + + if (digits) { + backtrack(0, ""); + } + + return res; +} diff --git a/typescript/191-Number-of-1-Bits.ts b/typescript/191-Number-of-1-Bits.ts new file mode 100644 index 000000000..72866886f --- /dev/null +++ b/typescript/191-Number-of-1-Bits.ts @@ -0,0 +1,12 @@ +function hammingWeight(n: number): number { + let base2 = n.toString(2).split(""); + let count = 0; + + base2.forEach((item) => { + if (item === "1") { + count += 1; + } + }); + + return count; +} diff --git a/typescript/198-House-Robber.ts b/typescript/198-House-Robber.ts new file mode 100644 index 000000000..b5efaa77c --- /dev/null +++ b/typescript/198-House-Robber.ts @@ -0,0 +1,12 @@ +function rob(nums: number[]): number { + let rob1 = 0; + let rob2 = 0; + + for (const n of nums) { + let temp = Math.max(n + rob1, rob2); + rob1 = rob2; + rob2 = temp; + } + + return rob2; +} diff --git a/typescript/20-Valid-Parentheses.ts b/typescript/20-Valid-Parentheses.ts new file mode 100644 index 000000000..bf817cdcc --- /dev/null +++ b/typescript/20-Valid-Parentheses.ts @@ -0,0 +1,28 @@ +function isValid(s: string): boolean { + const closingToOpening = { + "}": "{", + "]": "[", + ")": "(", + }; + const stack: string[] = []; + const chars = s.split(""); + + for (let i = 0; i < chars.length; i++) { + const element = chars[i]; + if (element in closingToOpening) { + const pop = stack.pop(); + + if (closingToOpening[element] === pop) { + continue; + } else { + return false; + } + } else { + stack.push(element); + } + } + + if (stack.length > 0) return false; + + return true; +} diff --git a/typescript/202-Happy-Number.ts b/typescript/202-Happy-Number.ts new file mode 100644 index 000000000..9d126d4d3 --- /dev/null +++ b/typescript/202-Happy-Number.ts @@ -0,0 +1,25 @@ +function isHappy(n: number): boolean { + const visit = new Set(); + + while (!visit.has(n)) { + visit.add(n); + n = sumOfSquares(n); + + if (n == 1) return true; + } + + return false; +} + +function sumOfSquares(n: number): number { + let output = 0; + + while (n) { + let digit = n % 10; + digit = digit ** 2; + output += digit; + n = Math.floor(n / 10); + } + + return output; +} diff --git a/typescript/208-Implement-Trie.ts b/typescript/208-Implement-Trie.ts new file mode 100644 index 000000000..c4b6aeec7 --- /dev/null +++ b/typescript/208-Implement-Trie.ts @@ -0,0 +1,61 @@ +class TrieNode { + children: {}; + endOfWord: boolean; + constructor() { + this.children = {}; + this.endOfWord = false; + } +} + +class Trie { + root: TrieNode; + constructor() { + this.root = new TrieNode(); + } + + insert(word: string): void { + let cur = this.root; + + for (const c of word) { + if (!(c in cur.children)) { + cur.children[c] = new TrieNode(); + } + cur = cur.children[c]; + } + cur.endOfWord = true; + } + + search(word: string): boolean { + let cur = this.root; + + for (const c of word) { + if (!(c in cur.children)) { + return false; + } + cur = cur.children[c]; + } + + return cur.endOfWord; + } + + startsWith(prefix: string): boolean { + let cur = this.root; + + for (const c of prefix) { + if (!(c in cur.children)) { + return false; + } + cur = cur.children[c]; + } + + return true; + } +} + +const trie = new Trie(); +trie.insert("apple"); +trie.search("apple"); // return True +trie.search("app"); // return False +trie.startsWith("app"); // return True +trie.insert("app"); +trie.search("app"); // return True diff --git a/typescript/211-Design-Add-and-Search-Words-Data-Structure.ts b/typescript/211-Design-Add-and-Search-Words-Data-Structure.ts new file mode 100644 index 000000000..3e92596ae --- /dev/null +++ b/typescript/211-Design-Add-and-Search-Words-Data-Structure.ts @@ -0,0 +1,57 @@ +class TrieNode { + children: { [key: string]: TrieNode }; + endOfWord: boolean; + constructor() { + this.children = {}; + this.endOfWord = false; + } +} + +class WordDictionary { + root: TrieNode; + constructor() { + this.root = new TrieNode(); + } + + addWord(word: string): void { + let cur = this.root; + + for (const c of word) { + if (!(c in cur.children)) { + cur.children[c] = new TrieNode(); + } + cur = cur.children[c]; + } + cur.endOfWord = true; + } + + search(word: string): boolean { + function dfs(j: number, root: TrieNode): boolean { + let cur = root; + + for (let i = j; i < word.length; i++) { + const c = word[i]; + + if (c === ".") { + for (const key in cur.children) { + if (Object.prototype.hasOwnProperty.call(cur.children, key)) { + const child = cur.children[key]; + if (dfs(i + 1, child)) { + return true; + } + } + } + return false; + } else { + if (!(c in cur.children)) { + return false; + } + cur = cur.children[c]; + } + } + + return cur.endOfWord; + } + return dfs(0, this.root); + } +} diff --git a/typescript/213-House-Robber-II.ts b/typescript/213-House-Robber-II.ts new file mode 100644 index 000000000..91ff332f7 --- /dev/null +++ b/typescript/213-House-Robber-II.ts @@ -0,0 +1,20 @@ +function helper(nums: number[]): number { + let rob1 = 0; + let rob2 = 0; + + for (const n of nums) { + let temp = Math.max(n + rob1, rob2); + rob1 = rob2; + rob2 = temp; + } + + return rob2; +} + +function rob(nums: number[]): number { + return Math.max( + nums[0], + helper(nums.slice(0, nums.length - 1)), + helper(nums.slice(1)) + ); +} diff --git a/typescript/22-Generate-Parentheses.ts b/typescript/22-Generate-Parentheses.ts new file mode 100644 index 000000000..13d2358b2 --- /dev/null +++ b/typescript/22-Generate-Parentheses.ts @@ -0,0 +1,27 @@ +function generateParenthesis(n: number): string[] { + const stack: string[] = []; + const res: string[] = []; + + function backtrack(openN: number, closedN: number) { + if (openN === n && closedN === n) { + res.push(stack.join("")); + return; + } + + if (openN < n) { + stack.push("("); + backtrack(openN + 1, closedN); + stack.pop(); + } + + if (closedN < openN) { + stack.push(")"); + backtrack(openN, closedN + 1); + stack.pop(); + } + } + + backtrack(0, 0); + + return res; +} diff --git a/typescript/226-Invert-Binary-Tree.ts b/typescript/226-Invert-Binary-Tree.ts new file mode 100644 index 000000000..7b98dd7c3 --- /dev/null +++ b/typescript/226-Invert-Binary-Tree.ts @@ -0,0 +1,27 @@ +/** + * Definition for a binary tree node. + * 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) + * } + * } + */ + +function invertTree(root: TreeNode | null): TreeNode | null { + let temp: TreeNode | null; + + if (!root) return null; + + if (root.left || root.right) { + temp = root.left; + root.left = invertTree(root.right); + root.right = invertTree(temp); + } + + return root; +} diff --git a/typescript/235-Lowest-Common-Ancestor-of-a-Binary Search-Tree.ts b/typescript/235-Lowest-Common-Ancestor-of-a-Binary Search-Tree.ts new file mode 100644 index 000000000..e092dd80f --- /dev/null +++ b/typescript/235-Lowest-Common-Ancestor-of-a-Binary Search-Tree.ts @@ -0,0 +1,27 @@ +/** + * Definition for a binary tree node. + * 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) + * } + * } + */ + +function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null ): TreeNode | null { + let cur = root; + + while (cur) { + if (p.val > cur.val && q.val > cur.val) { + cur = cur.right; + } else if (p.val < cur.val && q.val < cur.val) { + cur = cur.left; + } else { + return cur; + } + } +} diff --git a/typescript/242-Valid-Anagram.ts b/typescript/242-Valid-Anagram.ts new file mode 100644 index 000000000..a38912fc6 --- /dev/null +++ b/typescript/242-Valid-Anagram.ts @@ -0,0 +1,20 @@ +function isAnagram(s: string, t: string) { + if (s.length !== t.length) return false; + + let first: Array = s.split(""); + const second = t.split(""); + + for (let i = 0; i < second.length; i++) { + const element = second[i]; + + let found = first.indexOf(element); + + if (found !== -1) { + first[found] = null; + } else { + return false; + } + } + + return true; +} diff --git a/typescript/287-Find-the-Duplicate-Number.ts b/typescript/287-Find-the-Duplicate-Number.ts new file mode 100644 index 000000000..ed3fee9c5 --- /dev/null +++ b/typescript/287-Find-the-Duplicate-Number.ts @@ -0,0 +1,33 @@ +/** + * Definition for singly-linked list. + * 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 findDuplicate(nums: number[]): number { + let slow = 0; + let fast = 0; + while (true) { + slow = nums[slow]; + fast = nums[nums[fast]]; + if (slow == fast) { + break; + } + } + let slow2 = 0; + + while (true) { + slow = nums[slow]; + slow2 = nums[slow2]; + if (slow == slow2) { + break; + } + } + return slow; +} diff --git a/typescript/3-Longest-Substring-Without-Repeating-Characters.ts b/typescript/3-Longest-Substring-Without-Repeating-Characters.ts new file mode 100644 index 000000000..bd48df17b --- /dev/null +++ b/typescript/3-Longest-Substring-Without-Repeating-Characters.ts @@ -0,0 +1,15 @@ +function lengthOfLongestSubstring(s: string): number { + const charSet = new Set(); + let l = 0; + let res = 0; + + for (let r = 0; r < s.length; r++) { + while (charSet.has(s[r])) { + charSet.delete(s[l]); + l += 1; + } + charSet.add(s[r]); + res = Math.max(res, r - l + 1); + } + return res; +} diff --git a/typescript/300-Longest-Increasing-Subsequence.ts b/typescript/300-Longest-Increasing-Subsequence.ts new file mode 100644 index 000000000..2e2047309 --- /dev/null +++ b/typescript/300-Longest-Increasing-Subsequence.ts @@ -0,0 +1,13 @@ +function lengthOfLIS(nums: number[]): number { + const lis = Array(nums.length).fill(1); + + for (let i = nums.length - 1; i > -1; i--) { + for (let j = i + 1; j < nums.length; j++) { + if (nums[i] < nums[j]) { + lis[i] = Math.max(lis[i], 1 + lis[j]); + } + } + } + + return Math.max(...lis); +} diff --git a/typescript/322-Coin-Change.ts b/typescript/322-Coin-Change.ts new file mode 100644 index 000000000..5ef66d52f --- /dev/null +++ b/typescript/322-Coin-Change.ts @@ -0,0 +1,15 @@ +function coinChange(coins: number[], amount: number): number { + const dp = Array(amount + 1).fill(amount + 1); + + dp[0] = 0; + + for (let a = 1; a < amount + 1; a++) { + for (const c of coins) { + if (a - c >= 0) { + dp[a] = Math.min(dp[a], 1 + dp[a - c]); + } + } + } + + return dp[amount] != amount + 1 ? dp[amount] : -1; +} diff --git a/typescript/338-Counting-Bits.ts b/typescript/338-Counting-Bits.ts new file mode 100644 index 000000000..6a32a874f --- /dev/null +++ b/typescript/338-Counting-Bits.ts @@ -0,0 +1,22 @@ +function countBits(n: number): number[] { + const ans: number[] = []; + + for (let i = 0; i < n + 1; i++) { + ans.push(hammingWeight(i)); + } + + return ans; +} + +function hammingWeight(n: number): number { + let base2 = n.toString(2).split(""); + let count = 0; + + base2.forEach((item) => { + if (item === "1") { + count += 1; + } + }); + + return count; +} diff --git a/typescript/347-Top-K-Frequent-Elements.ts b/typescript/347-Top-K-Frequent-Elements.ts new file mode 100644 index 000000000..a94576870 --- /dev/null +++ b/typescript/347-Top-K-Frequent-Elements.ts @@ -0,0 +1,36 @@ +function topKFrequent(nums: number[], k: number): number[] | undefined { + const hash: { + [key: number]: number; + } = {}; + + const freq: number[][] = Array.apply(null, Array(nums.length + 1)).map( + () => [] + ); + + nums.forEach((item) => { + if (hash[item]) { + hash[item]++; + } else { + hash[item] = 1; + } + }); + + Object.keys(hash).forEach((item) => { + const key = Number(item); + const value = hash[item]; + freq[value].push(key); + }); + + const res: number[] = []; + + for (let i = freq.length - 1; i >= 0; i--) { + const element = freq[i]; + for (let j = 0; j < element.length; j++) { + const second = element[j]; + res.push(Number(second)); + if (res.length == k) { + return res; + } + } + } +} diff --git a/typescript/36-Valid-Sudoku.ts b/typescript/36-Valid-Sudoku.ts new file mode 100644 index 000000000..bb370a209 --- /dev/null +++ b/typescript/36-Valid-Sudoku.ts @@ -0,0 +1,37 @@ +function isValidSudoku(board: string[][]): boolean { + const rows = {}; + const cols = {}; + const squares = {}; + + for (let r = 0; r < 9; r++) { + for (let c = 0; c < 9; c++) { + const num = board[r][c]; + + if (num === ".") { + continue; + } + + const grid = `${Math.floor(r / 3)}${Math.floor(c / 3)}`; + + if (!cols[c]) { + cols[c] = new Set(); + } + if (!rows[r]) { + rows[r] = new Set(); + } + if (!squares[grid]) { + squares[grid] = new Set(); + } + + if (rows[r].has(num) || cols[c].has(num) || squares[grid].has(num)) { + return false; + } + + cols[c].add(num); + rows[r].add(num); + squares[grid].add(num); + } + } + + return true; +} diff --git a/typescript/39-Combination-Sum.ts b/typescript/39-Combination-Sum.ts new file mode 100644 index 000000000..21110ae20 --- /dev/null +++ b/typescript/39-Combination-Sum.ts @@ -0,0 +1,23 @@ +function combinationSum(candidates: number[], target: number): number[][] { + let res: number[][] = []; + + function dfs(i: number, cur: number[], total: number) { + if (total == target) { + res.push(cur.slice()); + return; + } + if (i >= candidates.length || total > target) { + return; + } + + cur.push(candidates[i]); + dfs(i, cur, total + candidates[i]); + + cur.pop(); + dfs(i + 1, cur, total); + } + + dfs(0, [], 0); + + return res; +} diff --git a/typescript/40-Combination-Sum-II.ts b/typescript/40-Combination-Sum-II.ts new file mode 100644 index 000000000..832224b8d --- /dev/null +++ b/typescript/40-Combination-Sum-II.ts @@ -0,0 +1,32 @@ +function combinationSum2(candidates: number[], target: number): number[][] { + candidates.sort(); + + const res: number[][] = []; + + function backtrack(cur: number[], pos: number, target: number) { + if (target === 0) { + res.push(cur.slice()); + } + if (target <= 0) { + return; + } + let prev = -1; + + for (let i = pos; i < candidates.length; i++) { + if (candidates[i] == prev) { + continue; + } + + cur.push(candidates[i]); + + backtrack(cur, i + 1, target - candidates[i]); + + cur.pop(); + prev = candidates[i]; + } + } + + backtrack([], 0, target); + + return res; +} diff --git a/typescript/42-Trapping-Rain-Water.ts b/typescript/42-Trapping-Rain-Water.ts new file mode 100644 index 000000000..f79345b21 --- /dev/null +++ b/typescript/42-Trapping-Rain-Water.ts @@ -0,0 +1,23 @@ +function trap(height: number[]): number { + if (!height) return 0; + + let l = 0; + let r = height.length - 1; + let leftMax = height[l]; + let rightMax = height[r]; + let res = 0; + + while (l < r) { + if (leftMax < rightMax) { + l += 1; + leftMax = Math.max(leftMax, height[l]); + res += leftMax - height[l]; + } else { + r -= 1; + rightMax = Math.max(rightMax, height[r]); + res += rightMax - height[r]; + } + } + + return res; +} diff --git a/typescript/46-Permutations.ts b/typescript/46-Permutations.ts new file mode 100644 index 000000000..319a5b17c --- /dev/null +++ b/typescript/46-Permutations.ts @@ -0,0 +1,25 @@ +function permute(nums: number[]): number[][] { + const res: number[][] = []; + + if (nums.length === 1) { + return [nums.slice()]; + } + + for (const i of nums) { + let n = nums.shift()!; + + let perms = permute(nums); + + for (const perm of perms) { + perm.push(n); + } + + perms.forEach((perm) => { + res.push(perm); + }); + + nums.push(n); + } + + return res; +} diff --git a/typescript/48-Rotate-Image.ts b/typescript/48-Rotate-Image.ts new file mode 100644 index 000000000..c6b46d522 --- /dev/null +++ b/typescript/48-Rotate-Image.ts @@ -0,0 +1,20 @@ +function rotate(matrix: number[][]): void { + let l = 0; + let r = matrix.length - 1; + + while (l < r) { + for (let i = 0; i < r - l; i++) { + let top = l; + let bottom = r; + + let topLeft = matrix[top][l + i]; + + matrix[top][l + i] = matrix[bottom - i][l]; + matrix[bottom - i][l] = matrix[bottom][r - i]; + matrix[bottom][r - i] = matrix[top + i][r]; + matrix[top + i][r] = topLeft; + } + r -= 1; + l += 1; + } +} diff --git a/typescript/49-Group-Anagrams.ts b/typescript/49-Group-Anagrams.ts new file mode 100644 index 000000000..532794768 --- /dev/null +++ b/typescript/49-Group-Anagrams.ts @@ -0,0 +1,46 @@ +function groupAnagrams(strs: string[]): string[][] { + const hash: { + [key: string]: string[]; + } = {}; + + strs.forEach((item, index) => { + let doesExist = false; + Object.keys(hash).forEach((key) => { + if (isAnagram(item, key)) { + hash[key].push(item); + doesExist = true; + } + }); + + if (!doesExist) { + hash[item] = [item]; + } + }); + + console.log(hash); + + return [...Object.keys(hash).map((k) => hash[k])]; +} + +console.log(groupAnagrams(["eat", "ate", "dog", "pog"])); + +function isAnagram(s: string, t: string) { + if (s.length !== t.length) return false; + + var first: Array = s.split(""); + const second = t.split(""); + + for (let i = 0; i < second.length; i++) { + const element = second[i]; + + let found = first.indexOf(element); + + if (found !== -1) { + first[found] = null; + } else { + return false; + } + } + + return true; +} diff --git a/typescript/5-Longest-Palindromic-Substring.ts b/typescript/5-Longest-Palindromic-Substring.ts new file mode 100644 index 000000000..491db9c40 --- /dev/null +++ b/typescript/5-Longest-Palindromic-Substring.ts @@ -0,0 +1,34 @@ +function longestPalindrome(s: string): string { + let res = ""; + let resLen = 0; + + for (let i = 0; i < s.length; i++) { + let l = i; + let r = i; + + while (l >= 0 && r < s.length && s[l] === s[r]) { + if (r - l + 1 > resLen) { + res = s.slice(l, r + 1); + resLen = r - l + 1; + } + + l -= 1; + r += 1; + } + + l = i; + r = i + 1; + + while (l >= 0 && r < s.length && s[l] === s[r]) { + if (r - l + 1 > resLen) { + res = s.slice(l, r + 1); + resLen = r - l + 1; + } + + l -= 1; + r += 1; + } + } + + return res; +} diff --git a/typescript/50-Pow.ts b/typescript/50-Pow.ts new file mode 100644 index 000000000..75415b3b1 --- /dev/null +++ b/typescript/50-Pow.ts @@ -0,0 +1,12 @@ +function myPow(x: number, n: number): number { + function helper(x: number, n: number): number { + if (x == 0) return 0; + if (n == 0) return 1; + + let res = helper(x * x, Math.floor(n / 2)); + return n % 2 ? x * res : res; + } + + let res = helper(x, Math.abs(n)); + return n >= 0 ? res : 1 / res; +} diff --git a/typescript/53-Maximum-Subarray.ts b/typescript/53-Maximum-Subarray.ts new file mode 100644 index 000000000..4a93edc4a --- /dev/null +++ b/typescript/53-Maximum-Subarray.ts @@ -0,0 +1,14 @@ +function maxSubArray(nums: number[]): number { + let maxSub = nums[0]; + let curSum = 0; + + for (const n of nums) { + if (curSum < 0) { + curSum = 0; + } + curSum += n; + maxSub = Math.max(maxSub, curSum); + } + + return maxSub; +} diff --git a/typescript/54-Spiral-Matrix.ts b/typescript/54-Spiral-Matrix.ts new file mode 100644 index 000000000..c73a031f9 --- /dev/null +++ b/typescript/54-Spiral-Matrix.ts @@ -0,0 +1,39 @@ +function spiralOrder(matrix: number[][]): number[] { + const res: number[] = []; + let left = 0; + let right = matrix[0].length; + let top = 0; + let bottom = matrix.length; + + while (left < right && top < bottom) { + // get every i in the top row + for (let i = left; i < right; i++) { + res.push(matrix[top][i]); + } + top += 1; + + // get every i in the right column + for (let i = top; i < bottom; i++) { + res.push(matrix[i][right - 1]); + } + right -= 1; + + if (!(left < right && top < bottom)) { + break; + } + + // get ever i in the bottom row + for (let i = right - 1; i > left - 1; i--) { + res.push(matrix[bottom - 1][i]); + } + bottom -= 1; + + // get evet i in the left column + for (let i = bottom - 1; i > top - 1; i--) { + res.push(matrix[i][left]); + } + left += 1; + } + + return res; +} diff --git a/typescript/543-Diameter-of-Binary-Tree.ts b/typescript/543-Diameter-of-Binary-Tree.ts new file mode 100644 index 000000000..cafb501d6 --- /dev/null +++ b/typescript/543-Diameter-of-Binary-Tree.ts @@ -0,0 +1,30 @@ +/** + * Definition for a binary tree node. + * 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) + * } + * } + */ + +function diameterOfBinaryTree(root: TreeNode | null): number { + let res = [0]; + + function dfs(root: TreeNode | null): number { + if (!root) return -1; + let left = dfs(root.left); + let right = dfs(root.right); + + res[0] = Math.max(res[0], 2 + left + right); + + return 1 + Math.max(left, right); + } + + dfs(root); + return res[0]; +} diff --git a/typescript/567-Permutation-in-String.ts b/typescript/567-Permutation-in-String.ts new file mode 100644 index 000000000..b66459a94 --- /dev/null +++ b/typescript/567-Permutation-in-String.ts @@ -0,0 +1,42 @@ +function checkInclusion(s1: string, s2: string): boolean { + if (s1.length > s2.length) return false; + + const s1Count = Array(26).fill(0); + const s2Count = Array(26).fill(0); + + for (let i = 0; i < s1.length; i++) { + s1Count[s1[i].charCodeAt(0) - "a".charCodeAt(0)] += 1; + s2Count[s2[i].charCodeAt(0) - "a".charCodeAt(0)] += 1; + } + + let matches = 0; + for (let i = 0; i < 26; i++) { + if (s1Count[i] == s2Count[i]) { + matches += 1; + } + } + + let l = 0; + for (let r = s1.length; r < s2.length; r++) { + if (matches == 26) return true; + + let index = s2[r].charCodeAt(0) - "a".charCodeAt(0); + s2Count[index] += 1; + if (s1Count[index] == s2Count[index]) { + matches += 1; + } else if (s1Count[index] + 1 == s2Count[index]) { + matches -= 1; + } + + let index2 = s2[l].charCodeAt(0) - "a".charCodeAt(0); + s2Count[index2] -= 1; + if (s1Count[index2] == s2Count[index2]) { + matches += 1; + } else if (s1Count[index2] - 1 == s2Count[index2]) { + matches -= 1; + } + l += 1; + } + + return matches == 26; +} diff --git a/typescript/572-Subtree-of-Another-Tree.ts b/typescript/572-Subtree-of-Another-Tree.ts new file mode 100644 index 000000000..8021fd450 --- /dev/null +++ b/typescript/572-Subtree-of-Another-Tree.ts @@ -0,0 +1,42 @@ +/** + * Definition for a binary tree node. + * 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) + * } + * } + */ + +function isSubtree(root: TreeNode | null, subRoot: TreeNode | null): boolean { + if (subRoot === null) return true; + if (root === null) return false; + + if (isSameTree(root, subRoot)) { + return true; + } + + let left = isSubtree(root.left, subRoot); + let right = isSubtree(root.right, subRoot); + + return left || right; +} + +function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean { + if (p === null && q === null) return true; + + if ((p === null && q !== null) || (p !== null && q === null)) return false; + + let leftSame = isSameTree(p.left, q.left); + let rightSame = isSameTree(p.right, q.right); + + if (p.val === q.val && leftSame && rightSame) { + return true; + } + + return false; +} diff --git a/typescript/62-Unique-Paths.ts b/typescript/62-Unique-Paths.ts new file mode 100644 index 000000000..753a4eadd --- /dev/null +++ b/typescript/62-Unique-Paths.ts @@ -0,0 +1,15 @@ +function uniquePaths(m: number, n: number): number { + let row = new Array(n).fill(1); + + for (let i = 0; i < m - 1; i++) { + let newRow = new Array(n).fill(1); + + for (let j = n - 2; j > -1; j--) { + newRow[j] = newRow[j + 1] + row[j]; + } + + row = newRow; + } + + return row[0]; +} diff --git a/typescript/647-Palindromic-Substrings.ts b/typescript/647-Palindromic-Substrings.ts new file mode 100644 index 000000000..a4956f49d --- /dev/null +++ b/typescript/647-Palindromic-Substrings.ts @@ -0,0 +1,25 @@ +function countSubstrings(s: string): number { + let res = 0; + + for (let i = 0; i < s.length; i++) { + let l = i; + let r = i; + + while (l >= 0 && r < s.length && s[l] === s[r]) { + res += 1; + l -= 1; + r += 1; + } + + l = i; + r = i + 1; + + while (l >= 0 && r < s.length && s[l] === s[r]) { + res += 1; + l -= 1; + r += 1; + } + } + + return res; +} diff --git a/typescript/66-Plus-One.ts b/typescript/66-Plus-One.ts new file mode 100644 index 000000000..9d0df0bab --- /dev/null +++ b/typescript/66-Plus-One.ts @@ -0,0 +1,6 @@ +function plusOne(digits: number[]): number[] { + return (BigInt(digits.join("")) + BigInt(1)) + .toString() + .split("") + .map((item) => Number(item)); +} diff --git a/typescript/70-Climbing-Stairs.ts b/typescript/70-Climbing-Stairs.ts new file mode 100644 index 000000000..72cf633a9 --- /dev/null +++ b/typescript/70-Climbing-Stairs.ts @@ -0,0 +1,11 @@ +function climbStairs(n: number): number { + let one = 1; + let two = 1; + + for (let i = 0; i < n - 1; i++) { + let temp = one; + one = one + two; + two = temp; + } + return one; +} diff --git a/typescript/704-Binary-Search.ts b/typescript/704-Binary-Search.ts new file mode 100644 index 000000000..8e91b4839 --- /dev/null +++ b/typescript/704-Binary-Search.ts @@ -0,0 +1,17 @@ +function search(nums: number[], target: number): number { + let l = 0, + r = nums.length - 1; + + while (l <= r) { + var m = Math.round((l + r) / 2); + if (nums[m] > target) { + r = m - 1; + } else if (nums[m] < target) { + l = m + 1; + } else { + return m; + } + } + + return -1; +} diff --git a/typescript/74-Search-a-2D-Matrix.ts b/typescript/74-Search-a-2D-Matrix.ts new file mode 100644 index 000000000..daea00e32 --- /dev/null +++ b/typescript/74-Search-a-2D-Matrix.ts @@ -0,0 +1,39 @@ +function searchMatrix(matrix: number[][], target: number): boolean { + const rows = matrix.length; + const columns = matrix[0].length; + + let top = 0; + let bot = rows - 1; + + while (top <= bot) { + let row = Math.floor((top + bot) / 2); + if (target > matrix[row][columns - 1]) { + top = row + 1; + } else if (target < matrix[row][0]) { + bot = row - 1; + } else { + break; + } + } + + if (top > bot) { + return false; + } + + let row = Math.floor((top + bot) / 2); + let l = 0; + let r = columns - 1; + + while (l <= r) { + let m = Math.floor((l + r) / 2); + if (target > matrix[row][m]) { + l = m + 1; + } else if (target < matrix[row][m]) { + r = m - 1; + } else { + return true; + } + } + + return false; +} diff --git a/typescript/746-Min-Cost-Climbing-Stairs.ts b/typescript/746-Min-Cost-Climbing-Stairs.ts new file mode 100644 index 000000000..e221f8b09 --- /dev/null +++ b/typescript/746-Min-Cost-Climbing-Stairs.ts @@ -0,0 +1,9 @@ +function minCostClimbingStairs(cost: number[]): number { + cost.push(0); + + for (let i = cost.length - 3; i > -1; i--) { + cost[i] += Math.min(cost[i + 1], cost[i + 2]); + } + + return Math.min(cost[0], cost[1]); +} diff --git a/typescript/78-Subsets.ts b/typescript/78-Subsets.ts new file mode 100644 index 000000000..6192016eb --- /dev/null +++ b/typescript/78-Subsets.ts @@ -0,0 +1,20 @@ +function subsets(nums: number[]): number[][] { + let res: number[][] = []; + let subset: number[] = []; + function dfs(i: number) { + if (i >= nums.length) { + res.push(subset.slice()); + return; + } + + subset.push(nums[i]); + dfs(i + 1); + + subset.pop(); + dfs(i + 1); + } + + dfs(0); + + return res; +} diff --git a/typescript/853-Car-Fleet.ts b/typescript/853-Car-Fleet.ts new file mode 100644 index 000000000..d5af3ff7b --- /dev/null +++ b/typescript/853-Car-Fleet.ts @@ -0,0 +1,25 @@ +function carFleet(target: number, position: number[], speed: number[]): number { + const combined = position + .map((item, index) => { + return [item, speed[index]]; + }) + .sort((a, b) => a[0] - b[0]); + + const stack: number[] = []; + + for (let i = combined.length - 1; i > -1; i--) { + const p = combined[i][0]; + const s = combined[i][1]; + + stack.push((target - p) / s); + + if ( + stack.length >= 2 && + stack[stack.length - 1] <= stack[stack.length - 2] + ) { + stack.pop(); + } + } + + return stack.length; +} diff --git a/typescript/875-Koko-Eating-Bananas.ts b/typescript/875-Koko-Eating-Bananas.ts new file mode 100644 index 000000000..24babca4c --- /dev/null +++ b/typescript/875-Koko-Eating-Bananas.ts @@ -0,0 +1,21 @@ +function minEatingSpeed(piles: number[], h: number): number { + let l = 1; + let r = Math.max(...piles); + let res = r; + + while (l <= r) { + let k = Math.floor((l + r) / 2); + let hours = 0; + for (const p of piles) { + hours += Math.ceil(p / k); + } + if (hours <= h) { + res = Math.min(res, k); + r = k - 1; + } else { + l = k + 1; + } + } + + return res; +} diff --git a/typescript/90-Subsets-II.ts b/typescript/90-Subsets-II.ts new file mode 100644 index 000000000..69f382244 --- /dev/null +++ b/typescript/90-Subsets-II.ts @@ -0,0 +1,26 @@ +function subsetsWithDup(nums: number[]): number[][] { + let res: number[][] = []; + nums.sort(); + + function backtrack(i: number, subset: number[]) { + if (i == nums.length) { + res.push(subset.slice()); + return; + } + + subset.push(nums[i]); + backtrack(i + 1, subset); + + subset.pop(); + + while (i + 1 < nums.length && nums[i] == nums[i + 1]) { + i += 1; + } + + backtrack(i + 1, subset); + } + + backtrack(0, []); + + return res; +} diff --git a/typescript/91-Decode-Ways.ts b/typescript/91-Decode-Ways.ts new file mode 100644 index 000000000..e4337c1d0 --- /dev/null +++ b/typescript/91-Decode-Ways.ts @@ -0,0 +1,20 @@ +function numDecodings(s: string): number { + let dp = { + [s.length]: 1, + }; + + for (let i = s.length - 1; i > -1; i--) { + if (s[i] == "0") { + dp[i] = 0; + } else { + dp[i] = dp[i + 1]; + } + if ( + i + 1 < s.length && + (s[i] == "1" || (s[i] == "2" && "0123456".includes(s[i + 1]))) + ) { + dp[i] += dp[i + 2]; + } + } + return dp[0]; +}