Binary Tree Path Sum and Construction Algorithms
To determine if a binary tree has a root-to-leaf path where the sum of node values equals a target, we can use a depth-first search approach:
/**
* @param {TreeNode} root
* @param {number} targetSum
* @return {boolean}
*/
function checkPathSum(root, targetSum) {
const traverse = (node, remaining) => {
// If we've reached a leaf node
if (!node.left && !node.right) {
return remaining === 0;
}
// Continue searching in left subtree
if (node.left) {
if (traverse(node.left, remaining - node.left.val)) {
return true;
}
}
// Continue searching in right subtree
if (node.right) {
if (traverse(node.right, remaining - node.right.val)) {
return true;
}
}
return false;
};
// Handle empty tree case
if (!root) return false;
// Start traversal with adjusted sum (subtracting root value)
return traverse(root, targetSum - root.val);
};
Path Sum II - Finding All Path
This problem extends the path sum concept to find all root-to-leaf paths that sum to a target value:
/**
* 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)
* }
*/
/**
* @param {TreeNode} root
* @param {number} targetSum
* @return {number[][]}
*/
function findAllPathSum(root, targetSum) {
const result = [];
const explore = (node, currentSum, path) => {
// Check if we've reached a valid leaf node
if (currentSum === 0 && !node.left && !node.right) {
result.push([...path]); // Create a copy of the current path
return;
}
// If we've reached an invalid leaf node
if (currentSum !== 0 && !node.left && !node.right) {
return;
}
// Explore left subtree
if (node.left) {
path.push(node.left.val);
explore(node.left, currentSum - node.left.val, path);
path.pop(); // Backtrack
}
// Explore right subtree
if (node.right) {
path.push(node.right.val);
explore(node.right, currentSum - node.right.val, path);
path.pop(); // Backtrack
}
};
// Handle empty tree case
if (!root) return [];
// Start exploration with root node
explore(root, targetSum - root.val, [root.val]);
return result;
};
Buidling Binary Tree from Inorder and Postorder Traversals
When constructing a binary tree from inorder and postorder traversal sequences, we can use the posotrder sequence to identify the root and then partition the inorder sequence:
/**
* 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)
* }
*/
/**
* @param {number[]} inorder
* @param {number[]} postorder
* @return {TreeNode}
*/
function constructFromInPost(inorder, postorder) {
// Create a map for quick index lookup
const indexMap = {};
for (let i = 0; i < inorder.length; i++) {
indexMap[inorder[i]] = i;
}
const build = (inStart, inEnd, postStart, postEnd) => {
// Base case: invalid range
if (postStart > postEnd || inStart > inEnd) {
return null;
}
// Root value is the last element in postorder
const rootValue = postorder[postEnd];
const rootIndex = indexMap[rootValue];
// Calculate number of nodes in left subtree
const leftSize = rootIndex - inStart;
// Create root node
const rootNode = new TreeNode(rootValue);
// Recursively build left and right subtrees
rootNode.left = build(inStart, rootIndex - 1, postStart, postStart + leftSize - 1);
rootNode.right = build(rootIndex + 1, inEnd, postStart + leftSize, postEnd - 1);
return rootNode;
};
return build(0, inorder.length - 1, 0, postorder.length - 1);
};
Building Binary Tree from Preorder and Inorder Traversals
Similar to the previous problem, but using preorder and inorder sequences to construct the binary tree:
/**
* 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)
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
function constructFromPreIn(preorder, inorder) {
// Create a map for quick index lookup
const indexMap = {};
for (let i = 0; i < inorder.length; i++) {
indexMap[inorder[i]] = i;
}
const build = (preStart, preEnd, inStart, inEnd) => {
// Base case: invalid range
if (preStart > preEnd || inStart > inEnd) {
return null;
}
// Root value is the first element in preorder
const rootValue = preorder[preStart];
const rootIndex = indexMap[rootValue];
// Calculate number of nodes in left subtree
const leftSize = rootIndex - inStart;
// Create root node
const rootNode = new TreeNode(rootValue);
// Recursively build left and right subtrees
rootNode.left = build(preStart + 1, preStart + leftSize, inStart, rootIndex - 1);
rootNode.right = build(preStart + leftSize + 1, preEnd, rootIndex + 1, inEnd);
return rootNode;
};
return build(0, preorder.length - 1, 0, inorder.length - 1);
};