Given a binary search tree (BST) where all node values are unique, and two nodes from the tree p and q, return the lowest common ancestor (LCA) of the two nodes.
The lowest common ancestor between two nodes p and q is the lowest node in a tree T such that both p and q as descendants. The ancestor is allowed to be a descendant of itself.
Example 1:
Input: root = [5,3,8,1,4,7,9,null,2], p = 3, q = 8
Output: 5Example 2:
Input: root = [5,3,8,1,4,7,9,null,2], p = 3, q = 4
Output: 3Explanation: The LCA of nodes 3 and 4 is 3, since a node can be a descendant of itself.
Constraints:
2 <= The number of nodes in the tree <= 100.-100 <= Node.val <= 100p != qp and q will both exist in the BST.
You should aim for a solution as good or better than O(h) time and O(h) space, where h is the height of the given tree.
A Binary Search Tree (BST) is a tree in which the values of all nodes in the left subtree of a node are less than the node's value, and the values of all nodes in the right subtree are greater than the node's value. Additionally, every subtree of a BST must also satisfy this property, meaning the "less than" or "greater than" condition is valid for all nodes in the tree, not just the root. How can you use this idea to find the LCA of the given nodes in the tree?
We can use recursion to traverse the tree. Can you figure out the conditions we encounter when choosing a path between the left and right subtrees during traversal using the values of the two given nodes? Perhaps you can determine the LCA by traversing based on these conditions.
If nodes p and q are in different subtrees, a split occurs, making the current node the LCA. If both are in the left or right subtree, the LCA lies in that subtree and we further choose that subtree to traverse using recursion. You should also handle other multiple scenarios to get the LCA.
The LCA can also be one of the nodes, p or q, if the current node is equal to either of them. This is because if we encounter either p or q during the traversal, that node is the LCA.
Before attempting this problem, you should be comfortable with:
We are working with a Binary Search Tree (BST), so:
For two nodes p and q:
root.p and q have values less than the current node's value:p and q have values greater than the current node's value:null.# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
if not root or not p or not q:
return None
if (max(p.val, q.val) < root.val):
return self.lowestCommonAncestor(root.left, p, q)
elif (min(p.val, q.val) > root.val):
return self.lowestCommonAncestor(root.right, p, q)
else:
return rootWhere is the height of the tree.
This is the iterative version of finding the Lowest Common Ancestor (LCA) in a Binary Search Tree (BST).
Because a BST is ordered:
We can decide where both nodes lie just by comparing values.
p and q are both greater than the current node -> move right.This avoids recursion and simply walks down the tree until the split point is found.
cur = root.cur is not null:p.val and q.val are both greater than cur.val -> go right.cur (the LCA).null if tree is empty (should not happen for valid input).# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
cur = root
while cur:
if p.val > cur.val and q.val > cur.val:
cur = cur.right
elif p.val < cur.val and q.val < cur.val:
cur = cur.left
else:
return curWhere is the height of the tree.
A common mistake is treating this problem like a general binary tree LCA problem. In a BST, values are ordered (left < node < right), which allows us to determine the direction to search based on value comparisons alone. Using a generic DFS approach that checks both subtrees wastes time and ignores the BST structure that makes O(h) solutions possible.
When comparing p and q values against the current node, be careful with the boundary conditions. The LCA is found when the current node's value lies between p.val and q.val (inclusive). A common bug is using strict inequalities everywhere, which fails when p or q equals the current node. Remember: if p.val <= root.val <= q.val (or vice versa), the current node is the LCA.