diff --git a/construct-binary-tree-from-preorder-and-inorder-traversal/HC-kang.ts b/construct-binary-tree-from-preorder-and-inorder-traversal/HC-kang.ts new file mode 100644 index 00000000..3d50de1f --- /dev/null +++ b/construct-binary-tree-from-preorder-and-inorder-traversal/HC-kang.ts @@ -0,0 +1,53 @@ +// 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; + } +} + +// T.C: O(N) +// S.C: O(N^2) - Slice makes n-1, n-2, ..., 1 for n times. So, it's O(N^2). +function buildTree(preorder: number[], inorder: number[]): TreeNode | null { + if (preorder.length === 0 || inorder.length === 0) { + return null; + } + const root = new TreeNode(preorder[0]); + const idx = inorder.indexOf(preorder[0]); + root.left = buildTree(preorder.slice(1, idx + 1), inorder.slice(0, idx)); + root.right = buildTree(preorder.slice(idx + 1), inorder.slice(idx + 1)); + + return root; +} + +// Not using slice. but I think it's not necessary... first solution is more readable. and that's not so bad. +// T.C: O(N) +// S.C: O(N) +function buildTree(preorder: number[], inorder: number[]): TreeNode | null { + // this tree is consist of unique values + const inorderMap = new Map(); + for (const [i, val] of inorder.entries()) { + inorderMap.set(val, i); + } + + function helper(preLeft: number, preRight: number, inLeft: number, inRight: number): TreeNode | null { + if (preLeft > preRight) return null; + + const rootValue = preorder[preLeft]; + const root = new TreeNode(rootValue); + const inRootIdx = inorderMap.get(rootValue)!; + + const leftSize = inRootIdx - inLeft; + + root.left = helper(preLeft + 1, preLeft + leftSize, inLeft, inRootIdx - 1); + root.right = helper(preLeft + leftSize + 1, preRight, inRootIdx + 1, inRight); + + return root; + } + + return helper(0, preorder.length - 1, 0, inorder.length - 1); +} diff --git a/counting-bits/HC-kang.ts b/counting-bits/HC-kang.ts new file mode 100644 index 00000000..dfde8558 --- /dev/null +++ b/counting-bits/HC-kang.ts @@ -0,0 +1,26 @@ +// T.C: O(n) +// S.C: O(n) +function countBits(n: number): number[] { + // T.C: O(1) + // S.C: O(1) + function countBit(num: number): number { + num = num - ((num >>> 1) & 0x55555555); + num = (num & 0x33333333) + ((num >>> 2) & 0x33333333); + num = (num + (num >>> 4)) & 0x0f0f0f0f; + num = num + (num >>> 8); + num = num + (num >>> 16); + return num & 0x3f; + } + + return new Array(n + 1).fill(0).map((_, i) => countBit(i)); +} + +// T.C: O(n) +// S.C: O(n) +function countBits(n: number): number[] { + const dp = new Array(n + 1).fill(0); + for (let i = 1; i <= n; i++) { + dp[i] = dp[i >> 1] + (i & 1); + } + return dp; +} diff --git a/decode-ways/HC-kang.ts b/decode-ways/HC-kang.ts new file mode 100644 index 00000000..0bff0344 --- /dev/null +++ b/decode-ways/HC-kang.ts @@ -0,0 +1,31 @@ +// T.C: O(n) +// S.C: O(n) +function numDecodings(s: string): number { + const NUM_OF_ALPHA = 26; + const memo = new Map(); + + function dfs(idx: number): number { + if (idx === s.length) { + return 1; + } + if (s[idx] === '0') { + return 0; + } + if (memo.has(idx)) { + return memo.get(idx)!; + } + + let count = dfs(idx + 1); + if ( + idx + 2 <= s.length && // check if idx + 2 is in the range + parseInt(s.slice(idx, idx + 2), 10) <= NUM_OF_ALPHA + ) { + count += dfs(idx + 2); + } + + memo.set(idx, count); + return count; + } + + return dfs(0); +} diff --git a/encode-and-decode-strings/HC-kang.ts b/encode-and-decode-strings/HC-kang.ts new file mode 100644 index 00000000..374679ca --- /dev/null +++ b/encode-and-decode-strings/HC-kang.ts @@ -0,0 +1,29 @@ +/** + * The most simple way + */ +function encode(strs: string[]): string { + return strs.join('🏖️'); +}; +function decode(s: string): string[] { + return s.split('🏖️'); +}; + +// T.C: O(n) +// S.C: O(n) +function encode(strs: string[]): string { + return strs.map((s) => s.length + '#' + s).join(''); +} + +// T.C: O(n) +// S.C: O(n) +function decode(s: string): string[] { + const res: string[] = []; + let curIdx = 0; + while (curIdx < s.length) { + const sepIdx = s.indexOf('#', curIdx); + const len = parseInt(s.slice(curIdx, sepIdx), 10); + res.push(s.slice(sepIdx + 1, sepIdx + 1 + len)); + curIdx = sepIdx + 1 + len; + } + return res; +} diff --git a/valid-anagram/HC-kang.ts b/valid-anagram/HC-kang.ts new file mode 100644 index 00000000..7af2f2b7 --- /dev/null +++ b/valid-anagram/HC-kang.ts @@ -0,0 +1,16 @@ +// T.C: O(n) +// S.C: O(1) +function isAnagram(s: string, t: string): boolean { + if (s.length !== t.length) return false; + + const NUM_OF_ALPHA = 26; + const A_CODE = 'a'.charCodeAt(0); + const bucket = new Array(NUM_OF_ALPHA).fill(0); // S.C: O(1) + + for (let i = 0; i < s.length; i++) { // T.C: O(n) + bucket[s.charCodeAt(i) - A_CODE]++; + bucket[t.charCodeAt(i) - A_CODE]--; + } + + return bucket.every(count => count === 0); +}