# 235. Lowest Common Ancestor of a Binary Search Tree
LeetCode Problem Link (opens new window)
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two specified nodes in the BST.
According to the definition in Baidu Encyclopedia: “For the root tree T, the LCA of two nodes p and q is defined as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”
Example given the following BST: root = [6,2,8,0,4,7,9,null,null,3,5]

Example 1:
- Input:
root = [6,2,8,0,4,7,9,null,null,3,5],p = 2,q = 8 - Output: 6
- Explanation: The LCA of nodes 2 and 8 is 6.
Example 2:
- Input:
root = [6,2,8,0,4,7,9,null,null,3,5],p = 2,q = 4 - Output: 2
- Explanation: The LCA of nodes 2 and 4 is 2 since a node can be a descendant of itself as per the definition.
Note:
- All nodes' values are unique.
- p and q are different nodes and both of them exist in the BST.
# Thought Process
If you have solved the 0236.Lowest Common Ancestor of a Binary Tree (opens new window), you would know that finding common ancestors can involve backtracking from the bottom up, where a node whose left subtree contains p and right subtree contains q would be the LCA.
This problem, however, is different because it's a binary search tree, which has ordered nodes. We can take advantage of this characteristic.
In an ordered tree, how do you know if p is in the left subtree of a node and q in the right?
Since it's an ordered tree, if a node is the common ancestor, its value must be within the range [p, q]. In other words, a node is the LCA if node > p && node < q or node > q && node < p.
Thus, while traversing from the top down, the first time we encounter a node falling within the value range [p.val, q.val], it can be concluded that this node is the LCA of p and q.
Consider moving through the tree as follows:
Example:
- If
p = 6andq = 9:

Following the directed path will directly locate node 8 as the LCA efficiently without traversing the entire tree.
# Recursive Approach
Following the three-step recursive breakdown:
- Define the Recursive Function's Return Value and Parameters
The parameters will be the current node and two nodes p, q.
The return value should be the LCA node, hence TreeNode *.
Code:
TreeNode* traverse(TreeNode* current, TreeNode* p, TreeNode* q)
- Define the Termination Condition
Returning when encountering a null node is adequate:
if (current == NULL) return current;
For this problem, encountering a null node is not possible since it is guaranteed p and q exist in the tree.
- Define Logic within a Single Recursive Layer
While traversing the BST, the key is to look for the range [p->val, q->val] (or [q->val, p->val]).
If the current node val is greater than both p.val and q.val, move left (implying the target range is on the left subtree).
Code:
if (current->val > p->val && current->val > q->val) {
TreeNode* left = traverse(current->left, p, q);
if (left != NULL) {
return left;
}
}
2
3
4
5
6
The recursion here involves returning early upon finding a non-null result as shown above.
If the current node val is smaller than both p.val and q.val, move right (target range on the right subtree).
if (current->val < p->val && current->val < q->val) {
TreeNode* right = traverse(current->right, p, q);
if (right != NULL) {
return right;
}
}
2
3
4
5
6
In remaining scenarios where the current node's value falls into (p->val <= current->val && current->val <= q->val) or the opposite, the current node is the LCA. Return current:
return current;
Full recursive code:
class Solution {
private:
TreeNode* traverse(TreeNode* current, TreeNode* p, TreeNode* q) {
if (current == nullptr) return current;
if (current->val > p->val && current->val > q->val) {
TreeNode* left = traverse(current->left, p, q);
if (left != nullptr) {
return left;
}
}
if (current->val < p->val && current->val < q->val) {
TreeNode* right = traverse(current->right, p, q);
if (right != nullptr) {
return right;
}
}
return current;
}
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
return traverse(root, p, q);
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Simplified code:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root->val > p->val && root->val > q->val) {
return lowestCommonAncestor(root->left, p, q);
} else if (root->val < p->val && root->val < q->val) {
return lowestCommonAncestor(root->right, p, q);
} else return root;
}
};
2
3
4
5
6
7
8
9
10
# Iterative Approach
Adopting the iterative approach for BST is straightforward due to its ordered nature, as previously elaborated in 0700.Search in a Binary Search Tree (opens new window).
Iterative code:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while(root) {
if (root->val > p->val && root->val > q->val) {
root = root->left;
} else if (root->val < p->val && root->val < q->val) {
root = root->right;
} else return root;
}
return nullptr;
}
};
2
3
4
5
6
7
8
9
10
11
12
13
The simplicity of the iterative approach, leveraging the order inherent in BSTs, should be clear.
# Conclusion
The LCA problem in binary search trees is more straightforward compared to 0236.Lowest Common Ancestor of a Binary Tree (opens new window). The BST's directionality facilitates direct traversal to locate the LCA upon encountering a node within the specified range.
Additionally, the iterative approach is even more intuitive than the recursive, again owing to the tree's ordering.
# Other Language Versions
# Java
Recursive approach:
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q);
if (root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q);
return root;
}
}
2
3
4
5
6
7
Iterative approach:
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while (true) {
if (root.val > p.val && root.val > q.val) {
root = root.left;
} else if (root.val < p.val && root.val < q.val) {
root = root.right;
} else {
break;
}
}
return root;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# Python
Recursive approach (Version 1)
class Solution:
def traverse(self, cur, p, q):
if cur is None:
return cur
if cur.val > p.val and cur.val > q.val:
left = self.traverse(cur.left, p, q)
if left is not None:
return left
if cur.val < p.val and cur.val < q.val:
right = self.traverse(cur.right, p, q)
if right is not None:
return right
return cur
def lowestCommonAncestor(self, root, p, q):
return self.traverse(root, p, q)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Recursive approach (Version 2) Simplified
class Solution:
def lowestCommonAncestor(self, root, p, q):
if root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
elif root.val < p.val and root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
else:
return root
2
3
4
5
6
7
8
9
Iterative approach
class Solution:
def lowestCommonAncestor(self, root, p, q):
while root:
if root.val > p.val and root.val > q.val:
root = root.left
elif root.val < p.val and root.val < q.val:
root = root.right
else:
return root
return None
2
3
4
5
6
7
8
9
10
# Go
Recursive approach
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
if root.Val > p.Val && root.Val > q.Val {
return lowestCommonAncestor(root.Left, p, q)
} else if root.Val < p.Val && root.Val < q.Val {
return lowestCommonAncestor(root.Right, p, q)
} else {
return root
}
}
2
3
4
5
6
7
8
9
Iterative approach
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
for root != nil {
if root.Val > p.Val && root.Val > q.Val {
root = root.Left
} else if root.Val < p.Val && root.Val < q.Val {
root = root.Right
} else {
return root
}
}
return nil
}
2
3
4
5
6
7
8
9
10
11
12
# JavaScript
Recursive approach:
var lowestCommonAncestor = function(root, p, q) {
if(root === null) {
return root;
}
if(root.val > p.val && root.val > q.val) {
return root.left = lowestCommonAncestor(root.left,p,q);
}
if(root.val < p.val && root.val < q.val) {
return root.right = lowestCommonAncestor(root.right,p,q);
}
return root;
};
2
3
4
5
6
7
8
9
10
11
12
Iterative approach
var lowestCommonAncestor = function(root, p, q) {
while(root) {
if(root.val > p.val && root.val > q.val) {
root = root.left;
}else if(root.val < p.val && root.val < q.val) {
root = root.right;
}else {
return root;
}
}
return null;
};
2
3
4
5
6
7
8
9
10
11
12
13
# TypeScript
Recursive approach:
function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
if (root.val > p.val && root.val > q.val)
return lowestCommonAncestor(root.left, p, q);
if (root.val < p.val && root.val < q.val)
return lowestCommonAncestor(root.right, p, q);
return root;
};
2
3
4
5
6
7
Iterative approach:
function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
while (root !== null) {
if (root.val > p.val && root.val > q.val) {
root = root.left;
} else if (root.val < p.val && root.val < q.val) {
root = root.right;
} else {
return root;
};
};
return null;
};
2
3
4
5
6
7
8
9
10
11
12
# Scala
Recursive:
object Solution {
def lowestCommonAncestor(root: TreeNode, p: TreeNode, q: TreeNode): TreeNode = {
if (root.value > p.value && root.value > q.value) lowestCommonAncestor(root.left, p, q)
else if (root.value < p.value && root.value < q.value) lowestCommonAncestor(root.right, p, q)
else root
}
}
2
3
4
5
6
7
Iterative:
object Solution {
def lowestCommonAncestor(root: TreeNode, p: TreeNode, q: TreeNode): TreeNode = {
var curNode = root
while(curNode != null){
if(curNode.value > p.value && curNode.value > q.value) curNode = curNode.left
else if(curNode.value < p.value && curNode.value < q.value) curNode = curNode.right
else return curNode
}
null
}
}
2
3
4
5
6
7
8
9
10
11
# Rust
Recursive:
impl Solution {
pub fn lowest_common_ancestor(
root: Option<Rc<RefCell<TreeNode>>>,
p: Option<Rc<RefCell<TreeNode>>>,
q: Option<Rc<RefCell<TreeNode>>>,
) -> Option<Rc<RefCell<TreeNode>>> {
let q_val = q.as_ref().unwrap().borrow().val;
let p_val = p.as_ref().unwrap().borrow().val;
let root_val = root.as_ref().unwrap().borrow().val;
if root_val > q_val && root_val > p_val {
return Self::lowest_common_ancestor(
root.as_ref().unwrap().borrow().left.clone(),
p,
q,
);
};
if root_val < q_val && root_val < p_val {
return Self::lowest_common_ancestor(
root.as_ref().unwrap().borrow().right.clone(),
p,
q,
);
}
root
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Iterative:
impl Solution {
pub fn lowest_common_ancestor(
mut root: Option<Rc<RefCell<TreeNode>>>,
p: Option<Rc<RefCell<TreeNode>>>,
q: Option<Rc<RefCell<TreeNode>>>,
) -> Option<Rc<RefCell<TreeNode>>> {
let p_val = p.unwrap().borrow().val;
let q_val = q.unwrap().borrow().val;
while let Some(node) = root.clone() {
let root_val = node.borrow().val;
if root_val > q_val && root_val > p_val {
root = node.borrow().left.clone();
} else if root_val < q_val && root_val < p_val {
root = node.borrow().right.clone();
} else {
return root;
}
}
None
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# C#
Recursive:
public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q)
{
if (root.val > p.val && root.val > q.val)
return LowestCommonAncestor(root.left, p, q);
if (root.val < p.val && root.val < q.val)
return LowestCommonAncestor(root.right, p, q);
return root;
}
2
3
4
5
6
7
8
Iterative:
public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q)
{
while (root != null)
{
if (root.val > p.val && root.val > q.val)
root = root.left;
else if (root.val < p.val && root.val < q.val)
root = root.right;
else return root;
}
return null;
}
2
3
4
5
6
7
8
9
10
11
12