diff --git a/javascript/100-Same-Tree.js b/javascript/100-Same-Tree.js index d313fcda0..b875bca3b 100644 --- a/javascript/100-Same-Tree.js +++ b/javascript/100-Same-Tree.js @@ -1,18 +1,71 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } + * https://leetcode.com/problems/same-tree/ + * TIme O(N) | Space O(H) + * @param {TreeNode} p + * @param {TreeNode} q + * @return {boolean} */ +var isSameTree = function(p, q) { + const isBaseCase = !(p || q); + if (isBaseCase) return true; + + const isBalanced = (p && q); + if (!isBalanced) return false; + + const isSame = p.val === q.val; + if (!isSame) return false; + + return dfs(p, q); +}; + +const dfs = (p, q) => { + const left = isSameTree(p.left, q.left); + const right = isSameTree(p.right, q.right); + + return left && right; +} + /** + * https://leetcode.com/problems/same-tree/ + * TIme O(N) | Space O(W) * @param {TreeNode} p * @param {TreeNode} q * @return {boolean} */ -var isSameTree = function (p, q) { - if (!p && !q) return true; - if (!p || !q || p.val !== q.val) return false; - return isSameTree(p.right, q.right) && isSameTree(p.left, q.left); -}; +var isSameTree = function(p, q) { + if (isSameNode(p, q)) return true; + + return bfs([[ p, q ]]); +} + +const bfs = (queue) => { + while (queue.length) { + for (let i = (queue.length - 1); 0 <= i; i--) { + const [ p, q ] = queue.shift(); + + if (!isSame(p, q)) return false; + + if (p.left) queue.push([ p.left, q.left ]); + if (p.right) queue.push([ p.right, q.right ]); + } + } + + return true; +} + +const isSameNode = (p, q) => { + const isBaseCase = !(p || q); + if (isBaseCase) return true; + + const isBalanced = (p && q); + if (!isBalanced) return false; + + const isSame = p.val === q.val; + if (!isSame) return false; + + return true; +} + +const isSame = (p, q) => isSameNode(p, q) + && isSameNode(p.left, q.left) + && isSameNode(p.right, q.right); diff --git a/javascript/102-Binary-Tree-Level-Order-Traversal.js b/javascript/102-Binary-Tree-Level-Order-Traversal.js index 82749f618..7134687f6 100644 --- a/javascript/102-Binary-Tree-Level-Order-Traversal.js +++ b/javascript/102-Binary-Tree-Level-Order-Traversal.js @@ -1,32 +1,56 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } - */ -/** + * https://leetcode.com/problems/binary-tree-level-order-traversal/ + * Time O(N) | Space O(W) * @param {TreeNode} root * @return {number[][]} */ -var levelOrder = function (root) { - if (!root) return []; +var levelOrder = function(root) { + const isBaseCase = root === null; + if (isBaseCase) return []; - const result = []; - const queue = [root]; + return bfs([ root ]); +}; +const bfs = (queue, levels = []) => { while (queue.length) { - const numNodes = queue.length; - const temp = []; - for (let i = 0; i < numNodes; i++) { - const subtree = queue.shift(); - temp.push(subtree.val); - if (subtree.left !== null) queue.push(subtree.left); - if (subtree.right !== null) queue.push(subtree.right); + const level = []; + + for (let i = (queue.length - 1); 0 <= i; i--) { + const node = queue.shift(); + + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); + + level.push(node.val); } - result.push(temp); + + levels.push(level.slice()); } - return result; -}; + return levels; +} + +/** + * https://leetcode.com/problems/binary-tree-level-order-traversal/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {number[]} + */ + var levelOrder = function(root, level = 0, levels = []) { + const isBaseCase = root === null; + if (isBaseCase) return levels; + + const isLastNode = level === levels.length; + if (isLastNode) levels.push([]); + + levels[level].push(root.val); + + return dfs(root, level, levels); +} + +const dfs = (root, level, levels) => { + if (root.left) levelOrder(root.left, (level + 1), levels); + if (root.right) levelOrder(root.right, (level + 1), levels); + + return levels; +} diff --git a/javascript/104-Maximum-Depth-of-Binary-Tree.js b/javascript/104-Maximum-Depth-of-Binary-Tree.js index 276b51048..0607e0160 100644 --- a/javascript/104-Maximum-Depth-of-Binary-Tree.js +++ b/javascript/104-Maximum-Depth-of-Binary-Tree.js @@ -1,23 +1,50 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } + * https://leetcode.com/problems/maximum-depth-of-binary-tree/ + * TIme O(N) | Space O(N) + * @param {TreeNode} root + * @return {number} */ + var maxDepth = function(root) { + const isBaseCase = root === null; + if (isBaseCase) return 0; + + return dfs(root); +}; + +const dfs = (root) => { + const left = maxDepth(root.left); + const right = maxDepth(root.right); + + const height = Math.max(left, right); + + return height + 1; +} + /** + * https://leetcode.com/problems/maximum-depth-of-binary-tree/ + * TIme O(N) | Space O(N) * @param {TreeNode} root * @return {number} */ -var maxDepth = (root) => { - let maxDepth = 0; - let DFS = (node, depth) => { - if (!node) return maxDepth; - if (depth > maxDepth) maxDepth = depth; - DFS(node.right, depth + 1); - DFS(node.left, depth + 1); - }; - DFS(root, 1); - return maxDepth; -}; +var maxDepth = function(root) { + const isBaseCase = root === null; + if (isBaseCase) return 0; + + return bfs([[ root, 0 ]]); +} + +const bfs = (queue, height = 0) => { + while (queue.length) { + for (let i = (queue.length - 1); 0 <= i; i--) { + const [ root, depth ] = queue.shift(); + + height = Math.max(height, (depth + 1)); + + if (root.left) queue.push([ root.left, (depth + 1) ]); + if (root.right) queue.push([ root.right, (depth + 1) ]); + } + } + + return height; +} + diff --git a/javascript/105-Construct-Binary-Tree-from-Preorder-and-Inorder-Traversal.js b/javascript/105-Construct-Binary-Tree-from-Preorder-and-Inorder-Traversal.js index e37b0639b..53a6fccda 100644 --- a/javascript/105-Construct-Binary-Tree-from-Preorder-and-Inorder-Traversal.js +++ b/javascript/105-Construct-Binary-Tree-from-Preorder-and-Inorder-Traversal.js @@ -1,10 +1,62 @@ -function buildTree(preorder, inorder) { - if (!preorder.length || !inorder.length) return null; - - let root = new TreeNode(preorder[0]); - let mid = inorder.indexOf(preorder[0]); - - root.left = buildTree(preorder.slice(1, mid + 1), inorder.slice(0, mid)); - root.right = buildTree(preorder.slice(mid + 1), inorder.slice(mid + 1)); - return root; -} +/** + * https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ + * Time O(N^2) | Space(H) + * @param {number[]} preorder + * @param {number[]} inorder + * @return {TreeNode} + */ + var buildTree = function(preorder, inorder) { + const isBaseCase = !preorder.length || !inorder.length; + if (isBaseCase) return null; + + return dfs(preorder, inorder); +} + +var dfs = (preorder, inorder) => { + const { leftInorder, mid, rightInorder } = getPointers(preorder, inorder); + const root = new TreeNode(inorder[mid]); + + root.left = buildTree(preorder, leftInorder); + root.right = buildTree(preorder, rightInorder); + + return root; +} + +const getPointers = (preorder, inorder) => { + const next = preorder.shift(); + const mid = inorder.indexOf(next); + const leftInorder = inorder.slice(0, mid); + const rightInorder = inorder.slice(mid + 1); + + return { leftInorder, mid, rightInorder }; +} + +/** + * https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ + * Time O(N) | Space(H) + * @param {number[]} preorder + * @param {number[]} inorder + * @return {TreeNode} + */ + var buildTree = function(preorder, inorder, max = -Infinity, indices = { preorder: 0, inorder: 0 }) { + const isBaseCase = preorder.length <= indices.inorder; + if (isBaseCase) return null; + + const isAtEnd = inorder[indices.inorder] === max; + if (isAtEnd) { + indices.inorder++; + return null; + } + + return dfs(preorder, inorder, max, indices); +} + +var dfs = (preorder, inorder, max, indices) => { + const val = preorder[indices.preorder++] + const root = new TreeNode(val); + + root.left = buildTree(preorder, inorder, root.val, indices); + root.right = buildTree(preorder, inorder, max, indices); + + return root; +} diff --git a/javascript/110-Balanced-Binary-Tree.js b/javascript/110-Balanced-Binary-Tree.js index 1cefe4183..30dacdd8c 100644 --- a/javascript/110-Balanced-Binary-Tree.js +++ b/javascript/110-Balanced-Binary-Tree.js @@ -1,31 +1,78 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } + * https://leetcode.com/problems/balanced-binary-tree/ + * TIme O(N) | Space O(H) + * @param {TreeNode} root + * @return {boolean} */ +var isBalanced = function(root) { + const isBaseCase = root === null; + if (isBaseCase) return true; + if (!isAcceptableHeight(root)) return false; + if (!isChildBalanced(root)) return false; + + return true; +} + +const isChildBalanced = (root) => { + const left = isBalanced(root.left); + const right = isBalanced(root.right); + + return left && right +} + +const isAcceptableHeight = (root) => { + const left = getHeight(root.left); + const right = getHeight(root.right); + + const difference = Math.abs(left - right); + + return difference <= 1; +} + +const getHeight = (root) => { + const isBaseCase = root === null; + if (isBaseCase) return 0; + + return dfs(root); +} + +var dfs = (root) => { + const left = getHeight(root.left) + const right = getHeight(root.right); + + const height = Math.max(left, right); + + return height + 1; +} + /** + * https://leetcode.com/problems/balanced-binary-tree/ + * TIme O(N) | Space O(H) * @param {TreeNode} root * @return {boolean} */ -var isBalanced = function (root) { - const getHeight = (root) => { - if (!root) return [-1, true]; + var isBalanced = function (root) { + const [ _height, _isBalanced ] = isRootBalanced(root); - const [leftHeight, leftBalanced] = getHeight(root.left); - const [rightHeight, rightBalanced] = getHeight(root.right); + return _isBalanced; +}; - const balanced = - leftBalanced && - rightBalanced && - Math.abs(leftHeight - rightHeight) < 2; +var isRootBalanced = (root) => { + const isBaseCase = root === null + if (isBaseCase) return [ -1, true ]; - return [1 + Math.max(leftHeight, rightHeight), balanced]; - }; + return dfs(root) +} - const balanced = getHeight(root)[1]; +var dfs = (root) => { + const [ left, isLeftBalanced ] = isRootBalanced(root.left); + const [ right, isRightBalanced ] = isRootBalanced(root.right); + const [ height, difference ] = [ Math.max(left, right), Math.abs(left - right) ]; - return balanced; -}; + const isAcceptableHeight = difference <= 1; + const _isBalanced = isLeftBalanced && isRightBalanced; + + const _isRootBalanced = _isBalanced && isAcceptableHeight; + + return [ (height + 1), _isRootBalanced ]; +} diff --git a/javascript/124-Binary-Tree-Maximum-Path-Sum.js b/javascript/124-Binary-Tree-Maximum-Path-Sum.js index 75346df77..ad41a02c3 100644 --- a/javascript/124-Binary-Tree-Maximum-Path-Sum.js +++ b/javascript/124-Binary-Tree-Maximum-Path-Sum.js @@ -1,35 +1,28 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } - */ -/** + * https://leetcode.com/problems/binary-tree-maximum-path-sum/ + * Time O(N) | Space O(H) * @param {TreeNode} root * @return {number} */ -var maxPathSum = function (root) { - const res = [root.val]; + var maxPathSum = function(root, maxValue = [ -Infinity ]) { + pathSum(root, maxValue); - // return max path sum without split - function dfs(root) { - if (!root) { - return 0; - } + return maxValue[0]; +}; - let leftMax = dfs(root.left); - let rightMax = dfs(root.right); - leftMax = Math.max(leftMax, 0); - rightMax = Math.max(rightMax, 0); +const pathSum = (root, maxValue) => { + const isBaseCase = root === null; + if (isBaseCase) return 0; - // compute max path sum WITH split - res[0] = Math.max(res[0], root.val + leftMax + rightMax); + return dfs(root, maxValue); +} - return root.val + Math.max(leftMax, rightMax); - } +const dfs = (node, maxValue) => { + const left = Math.max(0, pathSum(node.left, maxValue)); + const right = Math.max(0, pathSum(node.right, maxValue)); + const sum = left + right + node.val; - dfs(root); - return res[0]; -}; + maxValue[0] = Math.max(maxValue[0], sum); + + return Math.max(left, right) + node.val; +} diff --git a/javascript/1448-Count-Good-Nodes-in-Binary-Tree.js b/javascript/1448-Count-Good-Nodes-in-Binary-Tree.js index 990f08607..21cfd6d56 100644 --- a/javascript/1448-Count-Good-Nodes-in-Binary-Tree.js +++ b/javascript/1448-Count-Good-Nodes-in-Binary-Tree.js @@ -1,20 +1,59 @@ -function goodNodes(root) { - let total = 0; - - function traverse(node, prev) { - if (!node) return; - - if (node.left || node.right) { - traverse(node.left, Math.max(node.val, prev)); - traverse(node.right, Math.max(node.val, prev)); - } - - if (node.val >= prev) { - total += 1; - } - } - - traverse(root, root.val); - - return total; -} +/** + * https://leetcode.com/problems/count-good-nodes-in-binary-tree/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {number} + */ + var goodNodes = function(root, max = -Infinity, total = [ 0 ]) { + count(root, max, total); + + return total[0] +}; + +const count = (root, max, total) => { + const isBaseCase = root === null; + if (isBaseCase) return 0; + + return dfs(root, max, total); +} + +const dfs = (root, max, total) => { + const isGood = max <= root.val + if (isGood) total[0]++; + + max = Math.max(max, root.val); + + count(root.left, max, total); + count(root.right, max, total); +} + +/** + * https://leetcode.com/problems/count-good-nodes-in-binary-tree/ + * Time O(N) | Space O(W) + * @param {TreeNode} root + * @return {number} + */ +var goodNodes = function(root, ) { + const isBaseCase = root === null; + if (isBaseCase) return 0 + + return bfs([[ root, -Infinity ]]); +} + +const bfs = (queue, total = 0) => { + while (queue.length) { + for (let i = (queue.length - 1); 0 <= i; i--) { + let [ root, max ] = queue.shift(); + + const isGood = max <= root.val; + if (isGood) total++; + + max = Math.max(max, root.val); + + if (root.right) queue.push([ root.right, max ]); + if (root.left) queue.push([ root.left, max ]); + } + } + + return total; +} diff --git a/javascript/199-binary-tree-right-side-view.js b/javascript/199-binary-tree-right-side-view.js index 87018b41b..35fb95b62 100644 --- a/javascript/199-binary-tree-right-side-view.js +++ b/javascript/199-binary-tree-right-side-view.js @@ -1,35 +1,55 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } - */ -/** + * https://leetcode.com/problems/binary-tree-right-side-view/ + * Time O(N) | Space O(W) * @param {TreeNode} root * @return {number[]} */ -var rightSideView = function (root) { - let result = []; - let queue = []; + var rightSideView = function(root) { + const isBaseCase = root === null; + if (isBaseCase) return []; - if (root === null) { - return []; - } + return bfs([ root ]); +}; + +const bfs = (queue, rightSide = []) => { + while (queue.length) { + let prev = null; - queue.push(root); - - while (queue.length > 0) { - let length = queue.length; - for (let i = 0; i < length; i++) { - let node = queue.shift(); - if (i === length - 1) { - result.push(node.val); - } - if (node.left !== null) queue.push(node.left); - if (node.right !== null) queue.push(node.right); + for (let i = (queue.length - 1); 0 <= i; i--) { + const node = queue.shift(); + + prev = node; + + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); } + + rightSide.push(prev.val); } - return result; -}; + + return rightSide; +} + +/** + * https://leetcode.com/problems/binary-tree-right-side-view/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {number[]} + */ + var rightSideView = function(root, level = 0, rightSide = []) { + const isBaseCase = root === null; + if (isBaseCase) return rightSide; + + const isLastNode = level === rightSide.length + if (isLastNode) rightSide.push(root.val); + + return dfs(root, level, rightSide) +} + +const dfs = (root, level, rightSide) => { + if (root.right) rightSideView(root.right, (level + 1), rightSide); + if (root.left) rightSideView(root.left, (level + 1), rightSide); + + return rightSide +} + diff --git a/javascript/226-Invert-Binary-Tree.js b/javascript/226-Invert-Binary-Tree.js index 726257aed..55438b15e 100644 --- a/javascript/226-Invert-Binary-Tree.js +++ b/javascript/226-Invert-Binary-Tree.js @@ -1,19 +1,54 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } + * https://leetcode.com/problems/invert-binary-tree/ + * TIme O(N) | Space O(N) + * @param {TreeNode} root + * @return {TreeNode} */ +var invertTree = (root) => { + const isBaseCase = root === null; + if (isBaseCase) return root; + + return dfs(root); +} + +const dfs = (root) => { + const left = invertTree(root.left); + const right = invertTree(root.right); + + root.left = right; + root.right = left; + + return root; +} + /** + * https://leetcode.com/problems/invert-binary-tree/ + * TIme O(N) | Space O(W) * @param {TreeNode} root * @return {TreeNode} */ -var invertTree = function (root) { - if (!root) return root; - let left = root.left; - root.left = invertTree(root.right); - root.right = invertTree(left); +var invertTree = (root,) => { + const isBaseCase = root === null; + if (isBaseCase) return root; + + bfs([ root ]); + return root; -}; +} + +const bfs = (queue) => { + while (queue.length) { + for (let i = (queue.length - 1); 0 <= i; i--) { + const node = queue.shift(); + const left = node.right; + const right = node.left; + + node.left = left; + node.right = right; + + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); + } + } +} + diff --git a/javascript/230-Kth-Smallest-Element-in-a-BST.js b/javascript/230-Kth-Smallest-Element-in-a-BST.js index 472fdbec4..3cb704080 100644 --- a/javascript/230-Kth-Smallest-Element-in-a-BST.js +++ b/javascript/230-Kth-Smallest-Element-in-a-BST.js @@ -1,21 +1,49 @@ -function kthSmallest(root, k) { - let n = 0; - const stack = []; - let cur = root; - - while (cur || stack) { - while (cur) { - stack.push(cur); - cur = cur.left; - } - - cur = stack.pop(); - n += 1; - - if (n == k) { - return cur.val; - } - - cur = cur?.right; - } -} +/** + * https://leetcode.com/problems/kth-smallest-element-in-a-bst/ + * Time O(N + K) | Space O(H) + * @param {TreeNode} root + * @param {number} k + * @return {number} + */ + var kthSmallest = function(root, k, inOrder = []) { + if (!root) return inOrder + + return dfs(root, k, inOrder); +}; + +const dfs = (root, k, inOrder) => { + if (root.left) kthSmallest(root.left, k, inOrder); + + inOrder.push(root.val); + + if (root.right) kthSmallest(root.right, k, inOrder); + + return inOrder[(k - 1)]; +} + +/** + * https://leetcode.com/problems/kth-smallest-element-in-a-bst/ + * Time O(N + K) | Space O(H) + * @param {TreeNode} root + * @param {number} k + * @return {number} + */ + var kthSmallest = function(root, k, stack = []) { + while (k--) { + root = moveLeft(root, stack); + + const isSmallest = k === 0; + if (isSmallest) return root.val; + + root = root.right; + } +} + +const moveLeft = (root, stack) => { + while (root !== null) { + stack.push(root); + root = root.left; + } + + return stack.pop(); +} diff --git a/javascript/235-lowest-common-ancestor-of-a-binary-search-tree.js b/javascript/235-lowest-common-ancestor-of-a-binary-search-tree.js index 89467df16..822b3904d 100644 --- a/javascript/235-lowest-common-ancestor-of-a-binary-search-tree.js +++ b/javascript/235-lowest-common-ancestor-of-a-binary-search-tree.js @@ -1,25 +1,45 @@ /** - * Definition for a binary tree node. - * function TreeNode(val) { - * this.val = val; - * this.left = this.right = null; - * } + * https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} */ + var lowestCommonAncestor = function(root, p, q) { + const isGreater = (p.val < root.val) && (q.val < root.val); + if (isGreater) return lowestCommonAncestor(root.left, p, q); + + const isLess = (root.val < p.val) && (root.val < q.val); + if (isLess) return lowestCommonAncestor(root.right, p, q); + + return root; +}; /** + * https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ + * Time O(N) | Space O(1) * @param {TreeNode} root * @param {TreeNode} p * @param {TreeNode} q * @return {TreeNode} */ -var lowestCommonAncestor = function (root, p, q) { + var lowestCommonAncestor = function(root, p, q) { while (root !== null) { - if (root.val < p.val && root.val < q.val) { + const isGreater = (root.val < p.val) && (root.val < q.val) + if (isGreater) { root = root.right; - } else if (root.val > p.val && root.val > q.val) { + continue; + } + + const isLess = (p.val < root.val) && (q.val < root.val);; + if (isLess) { root = root.left; - } else { - return root; + continue; } + + break; } + + return root; }; diff --git a/javascript/297-Serialize-And-Deserialize-Binary-Tree.js b/javascript/297-Serialize-And-Deserialize-Binary-Tree.js new file mode 100644 index 000000000..96c3341de --- /dev/null +++ b/javascript/297-Serialize-And-Deserialize-Binary-Tree.js @@ -0,0 +1,85 @@ +/** + * Encodes a tree to a single string. + * https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {string} + */ + var serialize = function(root, result = []) { + serial(root, result); + + return result; +}; + +const serial = (root, result) => { + const isBase = root === null; + if (isBase) return result.push(null); + + dfsSerialize(root, result); +} + +const dfsSerialize = (node, result) => { + result.push(node.val); + serial(node.left, result); + serial(node.right, result); +}; + +/** + * Encodes a tree to a single string. + * https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {string} + */ +var serialize = function(root) { + const isBaseCase = root === null; + if (isBaseCase) return [ null ]; + + return dfsSerializeIterative([ root ]); +}; + +const dfsSerializeIterative = (stack, result = []) => { + while (stack.length) { + const curr = stack.pop(); + + const isNull = curr === null; + if (isNull) { + result.push(null); + continue; + } + + result.push(curr.val); + stack.push(curr.right); + stack.push(curr.left); + } + + return result; +} + +/** +* Decodes your encoded data to tree. +* https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ +* Time O(N) | Space O(H) +* @param {string} data +* @return {TreeNode} +*/ +var deserialize = function(data) { + const isBaseCase = !data.length; + if (isBaseCase) return null; + + const val = data.shift(); + + const isNull = val === null; + if (isNull) return null; + + return dfsDeserialize(val, data) +}; + +const dfsDeserialize = (val, data) => { + const node = new TreeNode(val); + + node.left = deserialize(data); + node.right = deserialize(data); + + return node; +} diff --git a/javascript/297-Serialize-and-Deserialize-Binary-Tree.js b/javascript/297-Serialize-and-Deserialize-Binary-Tree.js index 30bd3d44c..96c3341de 100644 --- a/javascript/297-Serialize-and-Deserialize-Binary-Tree.js +++ b/javascript/297-Serialize-and-Deserialize-Binary-Tree.js @@ -1,62 +1,85 @@ -/** - * Definition for a binary tree node. - * function TreeNode(val) { - * this.val = val; - * this.left = this.right = null; - * } - */ - -/** - * Encodes a tree to a single string. - * - * @param {TreeNode} root - * @return {string} - */ -var serialize = function (root) { - const res = []; - - function dfs(node) { - if (!node) { - res.push('N'); - return; - } - - res.push(String(node.val)); - dfs(node.left); - dfs(node.right); - } - - dfs(root); - return res.join(','); -}; - -/** - * Decodes your encoded data to tree. - * - * @param {string} data - * @return {TreeNode} - */ -var deserialize = function (data) { - const vals = data.split(','); - let i = 0; - - function dfs() { - if (vals[i] === 'N') { - i++; - return null; - } - - const node = new TreeNode(parseInt(vals[i])); - i++; - node.left = dfs(); - node.right = dfs(); - return node; - } - - return dfs(); -}; - -/** - * Your functions will be called as such: - * deserialize(serialize(root)); - */ +/** + * Encodes a tree to a single string. + * https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {string} + */ + var serialize = function(root, result = []) { + serial(root, result); + + return result; +}; + +const serial = (root, result) => { + const isBase = root === null; + if (isBase) return result.push(null); + + dfsSerialize(root, result); +} + +const dfsSerialize = (node, result) => { + result.push(node.val); + serial(node.left, result); + serial(node.right, result); +}; + +/** + * Encodes a tree to a single string. + * https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {string} + */ +var serialize = function(root) { + const isBaseCase = root === null; + if (isBaseCase) return [ null ]; + + return dfsSerializeIterative([ root ]); +}; + +const dfsSerializeIterative = (stack, result = []) => { + while (stack.length) { + const curr = stack.pop(); + + const isNull = curr === null; + if (isNull) { + result.push(null); + continue; + } + + result.push(curr.val); + stack.push(curr.right); + stack.push(curr.left); + } + + return result; +} + +/** +* Decodes your encoded data to tree. +* https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ +* Time O(N) | Space O(H) +* @param {string} data +* @return {TreeNode} +*/ +var deserialize = function(data) { + const isBaseCase = !data.length; + if (isBaseCase) return null; + + const val = data.shift(); + + const isNull = val === null; + if (isNull) return null; + + return dfsDeserialize(val, data) +}; + +const dfsDeserialize = (val, data) => { + const node = new TreeNode(val); + + node.left = deserialize(data); + node.right = deserialize(data); + + return node; +} diff --git a/javascript/543-Diameter-Of-Binary-Tree.js b/javascript/543-Diameter-Of-Binary-Tree.js index cb004fc75..092d52b01 100644 --- a/javascript/543-Diameter-Of-Binary-Tree.js +++ b/javascript/543-Diameter-Of-Binary-Tree.js @@ -1,28 +1,30 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } - */ -/** + * https://leetcode.com/problems/diameter-of-binary-tree/ + * TIme O(N) | Space O(H) * @param {TreeNode} root * @return {number} */ -var diameterOfBinaryTree = function (root) { - let diameter = 0; +var diameterOfBinaryTree = function(root, max = [0]) { + diameterOfTree(root, max); - function dfs(root) { - if (root == null) return -1; + return max[0]; +}; - const left = dfs(root.left); - const right = dfs(root.right); - diameter = Math.max(diameter, 2 + left + right); +const diameterOfTree = (root, max) => { + const isBaseCase = root === null; + if (isBaseCase) return 0; - return 1 + Math.max(left, right); - } - dfs(root); + return dfs(root, max); +} - return diameter; -}; +const dfs = (root, max) => { + const left = diameterOfTree(root.left, max); + const right = diameterOfTree(root.right, max); + + const diameter = left + right; + max[0] = Math.max(max[0], diameter); + + const height = Math.max(left, right); + + return height + 1; +} \ No newline at end of file diff --git a/javascript/572-Subtree-of-Another-Tree.js b/javascript/572-Subtree-of-Another-Tree.js index dc4409720..286210e92 100644 --- a/javascript/572-Subtree-of-Another-Tree.js +++ b/javascript/572-Subtree-of-Another-Tree.js @@ -1,30 +1,96 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } - */ -/** + * https://leetcode.com/problems/subtree-of-another-tree/ * @param {TreeNode} root * @param {TreeNode} subRoot * @return {boolean} */ -var isSubtree = function (root, subRoot) { - // given two nodes are they the same? - const isSame = (n1, n2) => { - if (!n1 && !n2) return true; - if (!n1 || !n2 || n1.val !== n2.val) return false; - return isSame(n1.left, n2.left) && isSame(n1.right, n2.right); - }; - - // check if subRoot is subtree of root: - const DFS = (node) => { - if (!node) return false; - if (isSame(node, subRoot)) return true; - return DFS(node.left) || DFS(node.right); - }; - - return DFS(root); +var isSubtree = function(root, subRoot) { + if (!root) return false + + if (isSame(root, subRoot)) return true + + const hasLeftTree = isSubtree(root.left, subRoot) + const hasRightTree = isSubtree(root.right, subRoot) + + return hasLeftTree || hasRightTree }; + +const isSame = (root, subRoot) => { + const hasReachedEnd = !(root && subRoot) + if (hasReachedEnd) return root === subRoot + + const isMismatch = root.val !== subRoot.val + if (isMismatch) return false + + const isLeftSame = isSame(root.left, subRoot.left) + const isRightSame = isSame(root.right, subRoot.right) + + return isLeftSame && isRightSame +} + +const hash = (val) => require('crypto') + .createHash('md5') + .update(val) + .digest('hex') + +const merkle = (root) => { + if (!root) return '#' + + const { left, val, right } = root + + const leftMerkle = merkle(left) + const rightMerkle = merkle(right) + + const merkleVal = [ leftMerkle, val, rightMerkle ].join('') + const merkleHash = hash(merkleVal) + + root.merkle = merkleHash + + return root.merkle +} + +const search = (root, subRoot) => { + if (!root) return false + + const hasSamePath = root.merkle === subRoot.merkle + if (hasSamePath) return true + + const left = search(root.left, subRoot) + const right = search(root.right, subRoot) + + return left || right +} + +var isSubtree = function(root, subRoot) { + [ root, subRoot ].forEach(merkle) + + return search(root, subRoot) +} + +const hashify = (root, hash, postOrderKey) => { + if (!root) return '#' + + const left = hashify(root.left, hash, postOrderKey) + const right = hashify(root.right, hash, postOrderKey) + + const key = [left, root.val, right].join('') + + if (!hash.has(key)) { + hash.set(key, postOrderKey[0]) + postOrderKey[0]++ + } + + return hash.get(key) +} + +var isSubtree = function(root, subRoot, hash = new Map (), postOrderKey = [0]) { + hashify(root, hash, postOrderKey) + + const hashKey = [ + hashify(subRoot.left, hash, postOrderKey), + subRoot.val, + hashify(subRoot.right, hash, postOrderKey) + ].join('') + + return hash.has(hashKey) +} \ No newline at end of file diff --git a/javascript/98-Validate-Binary-Search-Tree.js b/javascript/98-Validate-Binary-Search-Tree.js index 62293d546..6b6cc12ee 100644 --- a/javascript/98-Validate-Binary-Search-Tree.js +++ b/javascript/98-Validate-Binary-Search-Tree.js @@ -1,31 +1,72 @@ /** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } + * https://leetcode.com/problems/validate-binary-search-tree/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {boolean} */ +var isValidBST = function(root, min = -Infinity, max = Infinity) { + const isBaseCase = root === null; + if (isBaseCase) return true; + + const isInvalid = (root.val <= min) || (max <= root.val); + if (isInvalid) return false; + + return dfs(root, min, max); +}; + +const dfs = (root, min, max) => { + const left = isValidBST(root.left, min, root.val); + const right = isValidBST(root.right, root.val, max); + + return left && right; +} +// TODO /** + * https://leetcode.com/problems/validate-binary-search-tree/ + * Time O(N) | Space O(H) * @param {TreeNode} root * @return {boolean} */ + var isValidBST = function(root, prev = [ null ]) { + const isBaseCase = root === null; + if (isBaseCase) return true; -var isValidBST = function (root) { - return validate(root, null, null); -}; + if (!isValidBST(root.left, prev)) return false; + + const isInvalid = (prev[0] !== null) && (root.val <= prev[0]); + if (isInvalid) return false; + + prev[0] = root.val; -function validate(root, max, min) { - if (!root) { - return true; - } else if ( - (max !== null && root.val >= max) || - (min !== null && root.val <= min) - ) { - return false; - } else - return ( - validate(root.left, root.val, min) && - validate(root.right, max, root.val) - ); + return isValidBST(root.right, prev); } + +/** + * https://leetcode.com/problems/validate-binary-search-tree/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {boolean} + */ +var isValidBST = function(root, stack = []) { + let prev = null; + + while (stack.length || root) { + moveLeft(stack, root); + root = stack.pop(); + + const isInvalid = prev && (root.val <= prev.val); + if (isInvalid) return false; + + prev = root; + root = root.right; + } + + return true; +} + +const moveLeft = (stack, root) => { + while (root) { + stack.push(root); + root = root.left; + } +} \ No newline at end of file