235. Lowest Common Ancestor of a Binary Search Tree

Iterative solution

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */

/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
var lowestCommonAncestor = function(root, p, q) {
    // Make p the lowest node
    if (p.val > q.val) {
        const temp = p;
        p = q;
        q = temp;
    }
    
    let curr = root;

    while(curr) {
        if (p.val < curr.val && q.val < curr.val) {
            curr = curr.left;
        } else if (p.val > curr.val && q.val > curr.val) {
            curr = curr.right;
        } else {
            return curr;
        }
    }
};

Recursive Solution

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */

/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
var lowestCommonAncestor = function(root, p, q) {
    if (!root) {
        return null;
    }
    
    // Make p the lowest node
    if (p.val > q.val) {
        const temp = p;
        p = q;
        q = temp;
    }
    
    if (root.val === p.val || root.val === q.val) {
        // Root is one of the searched nodes
        return root;
    } else if (p.val < root.val && q.val > root.val) {
        // Split. Root is the common ancestor.
        return root;
    } else if (p.val < root.val && q.val < root.val) {
        // Left sub-tree
        return lowestCommonAncestor(root.left, p, q);
    } else {
        // Right sub-tree
        return lowestCommonAncestor(root.right, p, q);
    }
};

Complexity

  • Time Complexity: O(logN), because we visit only one node for every level of the tree.
  • Space Complexity: O(1), there is no extra memory used. For the resursive approach is O(logN) because of the implicit call stack.

All Solutions