Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Binary Tree Path Sum and Construction Algorithms

Tech Jun 14 1

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);
};

Tags: binary-tree

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.