Coder's Cat

Lowest Common Ancestor of a Binary Search Tree

2020-04-11

In graph theory and computer science, the lowest common ancestor (LCA) of two nodes is the lowest node that has both of them as descendants.

Here is an example, given a Binary Search Tree:

file:img/CAPTURE-2020_04_11_lowest-common-ancestor-of-a-binary-search-tree.org_20200411_225813.png

LCA(2, 8) = 6 
LCA(4, 7) = 6
LCA(2, 5) = 2
LCA(0, 3) = 2

What’s Binary search tree

Binary search tree have two properties:

  • The value of right child is greater than node’s value
  • The value of left child is less than node’s value

Approach #1: Recursive Algorithm

If we traverse each node of binary search tree and comparing the values of p , q and current node’s value, there are four scenarios:

  • current node is NULL, we will return NULL as result
  • root’s value is in the range of values of p and q, root is the lowest common ancestor
  • root’s value is less than p and q, then lowest common ancestor will be in the left subtree
  • root’s value is greater than p and q, then the lowest common ancestor will be the right subtree.

    Time Complexity: O(N)

    Space Complexity: O(N) for recursion stack.

    class Solution {
    public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    if(root == NULL || p == NULL || q == NULL)
    return NULL; // scenario #1
    if((p->val <= root->val && root->val <= q->val) ||
    (p->val >= root->val && root->val >= q->val))
    return root; // scenario #2
    if(p->val < root->val && q->val < root->val) {
    return lowestCommonAncestor(root->left, p, q); // scenario #3
    }
    if(p->val > root->val && q->val > root->val) {
    return lowestCommonAncestor(root->right, p, q); // scenario #4
    }
    return NULL;
    }
    };

Approach #2: Iterative Algorithm

Iterative algorithm works similarly to the recursive algorithm, but we don’t need a stack to backtrace search. In fact, we only need to find the first node, which p and q begin to split, one of them is in this node’s left subtree, and the other is in the right subtree.

This algorithm is somehow similar to binary search.

Time Complexity: O(N)

Space Complexity: O(1)

class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
TreeNode* node = root;
while(node != NULL) {
if(node->val > p->val && node->val > q->val)
node = node->left;
else if(node->val < p->val && node->val < q->val)
node = node->right;
else
return node;
}
return NULL;
}
};

When the tree is not a binary search tree, but only a binary tree. The solution would be more complex. Please refer to Lowest Common Ancestor Of A Binary Tree.