Start learning free

LESSON 340 OF 438 · BINARY TREES

Lowest Common Ancestor in a BST in Java: O(h) Time, O(1) Space

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

    JAVA · BINARY TREES

    Lca In Bst in Java, explained

    Problem overview

    The method lowestCommonAncestor receives the root of a binary search tree and two values, p and q, that both exist in the tree. It returns the value of their lowest common ancestor: the deepest node that has both of them in its subtree. A node counts as its own ancestor, so if p is above q, the answer is p. The two values can also be equal.

    Take the tree with root 6, children 2 and 8, then 0 and 4 under 2, 7 and 9 under 8, and 3 and 5 under 4. For p = 2 and q = 8 the answer is 6: they lie on different sides of the root. For p = 2 and q = 4 the answer is 2, since 4 sits inside the subtree of 2. For p = 5 and q = 3 the answer is 4, the parent of both.

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

    Approach: walk down and stop where the paths split

    In a general binary tree, finding a common ancestor means searching both subtrees. A BST makes it easier, because every value in a node's left subtree is smaller than the node and every value in its right subtree is larger. Comparing p and q with the current node's value tells you where each of them lies.

    • If both are smaller than the node, both are in the left subtree, so the lowest common ancestor is there too. Go left.
    • If both are larger, go right.
    • Otherwise they are on different sides of the node, or one of them is the node itself. Moving down in either direction would leave one of them behind, so this node is the deepest one that has both below it (or at it). That is the answer.

    The walk starts at the root, which is always a common ancestor, and each step moves one level down while the answer stays inside the current subtree. It needs no recursion and no stack, so extra space is constant.

    On the example with p = 5 and q = 3: at 6, both values are smaller, so go left to 2. Both are larger than 2, so go right to 4. At 4, 5 is larger and 3 is smaller, so the paths split, and the answer is 4.

    Step by step

    1. Start a walker at the root. A TreeNode variable named node will move down the tree.
    2. Loop while node != null. Each pass looks at one node and either returns or moves one level down.
    3. Both values smaller: if p < node.val && q < node.val, set node = node.left.
    4. Both values larger: with an else if, set node = node.right when p and q are both greater than node.val.
    5. Otherwise return node.val. The values split here, or one equals node.val. This also covers the rule that a node is its own ancestor.
    6. Return -1 after the loop. Because p and q are in the tree, the loop always returns first. Java still requires every path of a method that returns an int to end in a return.

    The solution in Java

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

    Java details worth a closer look:

    • p and q are plain int values, not nodes, so they are compared with < and > directly. Had they been Integer objects, == would compare references, but ordering comparisons would still unbox them.
    • The method returns node.val, an int, rather than the node. The tree is only read, never changed.
    • The final return -1 is there for the compiler. Without it, the code would fail to compile with a "missing return statement" error, because the compiler can't prove the loop returns.
    • The three branches cover every case. The last else covers every case where the first two conditions are false: the values straddle the node, or at least one equals node.val.

    Complexity

    Time: O(h). Each pass of the loop moves one level down, so the loop runs at most h times, where h is the height of the tree. For a balanced tree that is O(log n), and for a tree that is a single chain it is O(n).

    Space: O(1). The only extra storage is the variable node. A recursive version would use O(h) stack space for the same walk.

    Edge cases and common mistakes

    • One value is an ancestor of the other. For p = 2 and q = 4, the walk reaches 2, where p is not smaller than the node, so neither of the first two conditions holds and 2 is returned. Using <= and >= in the first two conditions would walk past the answer.
    • p equals q. For p = q = 7 the walk goes right at 6, reaches 8 and goes left, and stops at 7, which is returned.
    • A single-node tree. Both values must equal the root's value, so the root is returned.
    • Treating it as a general tree. Searching both subtrees for p and q works but ignores the BST property and costs O(n).
    • Assuming p < q. The tests can give the values in either order. The conditions test both values against the node, so order doesn't matter.

    Testing

    With the example 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 = 7, q = 7 gives 7.
    • p = 3, q = 9 gives 6.
    Keep going with JavaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free