Start learning free

LESSON 339 OF 437 · BINARY TREES

Lowest Common Ancestor in a BST in C++: Iterative O(h) Walk

Practice O(n) Read the full explanation

Given the root of a binary search tree (BST) and two values p and q that are both in the tree, return the value of their lowest common ancestor.

The lowest common ancestor of p and q is the deepest node that has both of them in its subtree. A node counts as its own ancestor: if the node holding p is above the node holding q, the answer is p.

In a BST, every value in a node's left subtree is smaller than the node's value, and every value in its right subtree is larger.

The trees below are written in level order (top to bottom, left to right), with NULL for a missing child.

 

Example 1:

        6
      /   \
     2     8
    / \   / \
   0   4 7   9
      / \
     3   5

Input: root = [6,2,8,0,4,7,9,NULL,NULL,3,5], p = 2, q = 8
Output: 6
Explanation: 2 is in the left subtree of 6 and 8 is in its right subtree, so 6 is the deepest node that has both below it.

Example 2:

Input: root = [6,2,8,0,4,7,9,NULL,NULL,3,5], p = 2, q = 4
Output: 2
Explanation: 4 is in the subtree of 2, and a node counts as its own ancestor.

Example 3:

Input: root = [6,2,8,0,4,7,9,NULL,NULL,3,5], p = 5, q = 3
Output: 4
Explanation: 3 and 5 are the two children of 4, one on each side.

 

Constraints:

  • The number of nodes in the tree is in the range [1, 1000].
  • Each node value is between -104 and 104, and all values are different.
  • p and q are both values of nodes in the tree. They can be equal.

 

Follow up: Can you find it in O(h) time, where h is the height of the tree, using only O(1) extra space?
STEP 1 OF 6
    Ctrl + Enter to check

    C++ · BINARY TREES

    Lca In Bst in C++, explained

    Problem overview

    The function lowestCommonAncestor receives the root of a binary search tree and two values, p and q, that are both in the tree. It returns the value of their lowest common ancestor: the deepest node that has both values in its subtree. A node counts as its own ancestor, and p and q may be equal.

    In the tree with root 6, children 2 and 8, and 2 having children 0 and 4 (4 having children 3 and 5), the answers are:

    • p = 2, q = 8 gives 6: they sit on different sides of the root.
    • p = 2, q = 4 gives 2: 4 is inside the subtree of 2, and a node is its own ancestor.
    • p = 5, q = 3 gives 4: they are the two children of 4.

    The follow-up asks for O(h) time, where h is the height of the tree, and O(1) extra space. This lesson does exactly that.

    Approach: let the values choose the direction

    For a general binary tree you would have to search for both nodes. A BST gives more: everything smaller than a node's value is in its left subtree, and everything larger is in its right subtree. Start at the root, which is above everything and so is a common ancestor, and look for the lowest one:

    • If both p and q are smaller than the current value, they are both in the left subtree, and so is their lowest common ancestor. Go left.
    • If both are larger, go right.
    • Otherwise they are split: one is on each side, or one of them equals the current value. Going down either way would leave a value behind, so this node is the answer.

    Take p = 5, q = 3. At 6 both are smaller, so go to 2. At 2 both are larger, so go to 4. At 4, 5 is larger and 3 is smaller, so the values are split and the answer is 4.

    Each pass moves one level down, so the walk makes at most h passes. A recursive version would use O(h) stack space; a loop that only moves a pointer uses none.

    Step by step

    1. Start a pointer at the root. node is the node we are looking at; the root is a common ancestor, so we are never above the answer.
    2. Loop while node is not null. Each pass either returns or moves down one level.
    3. Both values smaller: join the two comparisons with && and move node to node->left.
    4. Both values larger: the mirrored case, in an else if, moves to node->right.
    5. Anything else: the values are on different sides, or one equals the node's value. Return node->val.
    6. Return -1 after the loop. Because p and q are in the tree, the loop always returns first. The line only gives the function a return value on every path.

    The solution in C++

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

    The C++ details worth a closer look:

    • Values, not nodes. p and q are plain int values, so they are compared directly with node->val. Nothing needs to be dereferenced.
    • NULL in the loop condition. A pointer is compared with NULL here, as in the lesson's TreeNode definition. nullptr is the modern spelling and works the same way.
    • Only a pointer moves. node = node->left changes the local pointer. It doesn't modify the tree and allocates nothing.
    • The final return -1. A non-void function that can reach its end without a return has undefined behaviour in C++ if that path is taken, and compilers warn about it. The extra line is dead code here, but it keeps the function well-formed. The value -1 is safe as a marker only because it's unreachable; node values can be negative too.

    Complexity

    Time: O(h). Every pass descends one level and the loop ends at the latest at the node where the paths to p and q split. For a balanced tree that is O(log n); for a tree that is a single chain it is O(n).

    Space: O(1). One pointer and no recursion.

    Edge cases and common mistakes

    • One value is an ancestor of the other. For p = 2, q = 4, at node 2 the check p < 2 fails, and so does p > 2, so the code returns 2. Using <= or >= in the first two branches would walk past the answer.
    • Equal values. p = q = 3 walks down to the node 3 and returns 3.
    • A single-node tree. The root is returned immediately.
    • Assuming the answer is always in the middle. It can be the root, one of the two values, or any node between them.
    • Using the BST property on the wrong tree. The direction rule relies on the ordering. In an unordered binary tree, comparing values says nothing about which subtree they are in.
    • Mixing up the two checks. Joining them with || would turn when only one value is smaller into a move left, which can lose the other value.

    Testing

    On the tree [6,2,8,0,4,7,9,NULL,NULL,3,5]:

    • p = 2, q = 8 gives 6.
    • p = 2, q = 4 gives 2.
    • p = 5, q = 3 gives 4.
    • p = 3, q = 3 gives 3.
    • p = 0, q = 5 gives 2.
    Keep going with C++About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free