LeetCode Problem Workspace
Lowest Common Ancestor of a Binary Search Tree
Find the lowest common ancestor (LCA) of two nodes in a binary search tree, using binary-tree traversal and state tracking.
4
Topics
6
Code langs
3
Related
Practice Focus
Medium · Binary-tree traversal and state tracking
Answer-first summary
Find the lowest common ancestor (LCA) of two nodes in a binary search tree, using binary-tree traversal and state tracking.
Ace coding interviews with Interview AiBoxInterview AiBox guidance for Binary-tree traversal and state tracking
The problem requires finding the lowest common ancestor (LCA) of two nodes in a binary search tree. A key concept involves binary-tree traversal and state tracking to determine the lowest common ancestor efficiently.
Problem Statement
Given a binary search tree (BST) and two nodes, p and q, you need to find the lowest common ancestor (LCA) of the two nodes. The LCA is defined as the lowest node in the tree that has both nodes as descendants. It is guaranteed that both nodes p and q will exist in the BST and that p is not equal to q.
To solve this problem, traverse the BST from the root. At each node, check the relative positions of p and q. If both p and q are in the left or right subtree of the current node, move in the respective direction. If p and q are in different subtrees, the current node is the LCA.
Examples
Example 1
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output: 6
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
The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.
Example 3
Input: root = [2,1], p = 2, q = 1
Output: 2
Example details omitted.
Constraints
- The number of nodes in the tree is in the range [2, 105].
- -109 <= Node.val <= 109
- All Node.val are unique.
- p != q
- p and q will exist in the BST.
Solution Approach
Binary Search Tree Property
Since the tree is a binary search tree, it has a property where for any node, values in the left subtree are smaller, and values in the right subtree are larger. This property helps in efficiently determining the direction of traversal (left or right) while searching for the LCA.
Depth-First Search (DFS)
Using a DFS traversal, we explore the tree starting from the root. At each node, check if both p and q lie in the left or right subtrees. If so, move to the respective subtree. If p and q lie in different subtrees, the current node is the LCA.
State Tracking for Efficient Search
Track the state of traversal to avoid unnecessary rechecking of nodes. By comparing the values of the current node with p and q, we can decide whether to move left or right or return the current node as the LCA.
Complexity Analysis
| Metric | Value |
|---|---|
| Time | Depends on the final approach |
| Space | Depends on the final approach |
The time complexity of the solution depends on the depth of the tree, which can be O(log n) for a balanced tree and O(n) for a skewed tree. The space complexity is O(1) for the iterative approach or O(h) for the recursive DFS approach, where h is the height of the tree.
What Interviewers Usually Probe
- Candidate correctly identifies the LCA concept and binary search tree traversal patterns.
- Candidate efficiently explains the use of DFS and state tracking in LCA search.
- Candidate discusses time and space complexities relevant to the tree's structure and traversal.
Common Pitfalls or Variants
Common pitfalls
- Confusing binary tree traversal with BFS, leading to inefficient solutions.
- Incorrectly identifying the LCA when both nodes are in the same subtree.
- Not considering the edge case where one of the nodes is the root.
Follow-up variants
- Find the LCA for multiple pairs of nodes in a single BST.
- Find the LCA in a binary tree (not necessarily a BST).
- Find the LCA in a tree with non-unique node values.
FAQ
How do I approach the Lowest Common Ancestor problem in a Binary Search Tree?
Start by utilizing the BST property to narrow down the search direction. Use DFS to explore the tree and track the state of traversal to identify the LCA.
What is the key traversal method for solving the Lowest Common Ancestor problem?
The primary traversal method is Depth-First Search (DFS), where you explore each subtree and determine if both nodes are present in the same subtree.
What should I consider when analyzing the time complexity for this problem?
The time complexity depends on the tree's height, which is O(log n) for a balanced tree and O(n) for a skewed tree. Space complexity is O(h) for a recursive approach.
What is the significance of the binary search tree property in this problem?
The binary search tree property allows for efficient traversal and narrowing down the search for the LCA by checking whether the nodes lie in the left or right subtree of the current node.
How can GhostInterview help me with the Lowest Common Ancestor problem?
GhostInterview provides a structured approach, highlighting the critical traversal patterns and common pitfalls to avoid, ensuring an efficient and clear solution.
Solution
Solution 1: Iteration
Starting from the root node, we traverse the tree. If the current node's value is less than both $\textit{p}$ and $\textit{q}$ values, it means that $\textit{p}$ and $\textit{q}$ should be in the right subtree of the current node, so we move to the right child. If the current node's value is greater than both $\textit{p}$ and $\textit{q}$ values, it means that $\textit{p}$ and $\textit{q}$ should be in the left subtree, so we move to the left child. Otherwise, it means the current node is the lowest common ancestor of $\textit{p}$ and $\textit{q}$, so we return the current node.
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(
self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode'
) -> 'TreeNode':
while 1:
if root.val < min(p.val, q.val):
root = root.right
elif root.val > max(p.val, q.val):
root = root.left
else:
return rootSolution 2: Recursion
We can also use a recursive approach to solve this problem.
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(
self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode'
) -> 'TreeNode':
while 1:
if root.val < min(p.val, q.val):
root = root.right
elif root.val > max(p.val, q.val):
root = root.left
else:
return rootContinue Topic
tree
Practice more edge cases under the same topic.
arrow_forwardauto_awesomeContinue Pattern
Binary-tree traversal and state tracking
Expand the same solving frame across more problems.
arrow_forwardsignal_cellular_altSame Difficulty Track
Medium
Stay on this level to stabilize interview delivery.
arrow_forward