The problem can be found at the following link: Question Link
Given a Binary Search Tree (BST) with unique values and two nodes n1
and n2
(where n1 != n2
), find the Lowest Common Ancestor (LCA) of the two given nodes in the BST.
The LCA is the lowest node in the BST that has both n1
and n2
as descendants (a node is also considered its own descendant).
5
/ \
4 6
/ \
3 7
\
8
n1 = 7
, n2 = 8

7
The lowest common ancestor of 7
and 8
is 7
itself.
20
/ \
8 22
/ \
4 12
/ \
10 14
n1 = 8
, n2 = 14

8
8
is the lowest node that is an ancestor of both 8
and 14
.
2
/ \
1 3
n1 = 1
, n2 = 3

2
2
is the lowest node that is an ancestor of both 1
and 3
.
$(1 \leq \text{Number of Nodes} \leq 10^5)$ $(1 \leq \text{node->data} \leq 10^5)$ $(1 \leq \text{Node Value}, n1, n2 \leq 10^5)$
- Start from the root of the BST.
- If
root->data
is greater than bothn1
andn2
, move to the left subtree. - If
root->data
is smaller than bothn1
andn2
, move to the right subtree. - Otherwise, return
root
as it is the Lowest Common Ancestor (LCA).
- Start at the root node.
- While
root
is notNULL
:- If
root->data > max(n1, n2)
, move left. - If
root->data < min(n1, n2)
, move right. - Otherwise, root is the LCA, return it.
- If
- Expected Time Complexity:
O(H)
, whereH
is the height of the BST. In a balanced BST,H = log N
, so this is efficient. - Expected Auxiliary Space Complexity:
O(1)
, as no additional data structures are used.
class Solution {
public:
Node* LCA(Node* root, Node* n1, Node* n2) {
while (root && (root->data > max(n1->data, n2->data) || root->data < min(n1->data, n2->data)))
root = (root->data > n1->data) ? root->left : root->right;
return root;
}
};
- Base case: If
root
isNULL
, returnNULL
. - If both
n1
andn2
are smaller, move left. - If both
n1
andn2
are greater, move right. - Otherwise, return
root
, as it's the LCA.
class Solution {
public:
Node* LCA(Node* root, Node* n1, Node* n2) {
if (!root || root->data == n1->data || root->data == n2->data) return root;
if (root->data > n1->data && root->data > n2->data) return LCA(root->left, n1, n2);
if (root->data < n1->data && root->data < n2->data) return LCA(root->right, n1, n2);
return root;
}
};
🔹 Pros: Simple and easy to understand.
🔹 Cons: Uses recursion stack space (O(H)
).
- Mimics recursion using an explicit stack.
- Instead of recursive calls, we use a while loop and a stack.
class Solution {
public:
Node* LCA(Node* root, Node* n1, Node* n2) {
stack<Node*> st;
while (root) {
if (root->data > n1->data && root->data > n2->data) root = root->left;
else if (root->data < n1->data && root->data < n2->data) root = root->right;
else return root;
}
return nullptr;
}
};
🔹 Pros: Avoids function call stack overflow.
🔹 Cons: Slightly more complex than recursion.
Approach | ⏱️ Time Complexity | 🗂️ Space Complexity | ⚡ Method | ✅ Pros | |
---|---|---|---|---|---|
Optimized Iterative | 🟢 O(H) |
🟢 O(1) |
Iterative | Best runtime and space efficiency | None |
Recursive | 🟢 O(H) |
🟡 O(H) |
Recursion | Simple and readable | Uses recursion stack space |
Iterative (Stack) | 🟢 O(H) |
🟢 O(1) |
Iterative | Mimics recursion without function calls | Slightly complex implementation |
- ✅ For best efficiency: Optimized Iterative Approach (
O(1)
space,O(H)
time). - ✅ For simplicity: Recursive approach.
- ✅ For avoiding recursion depth issues: Iterative (Stack-based) approach.
class Solution {
Node LCA(Node root, Node n1, Node n2) {
while (root != null && (root.data > Math.max(n1.data, n2.data) || root.data < Math.min(n1.data, n2.data)))
root = (root.data > n1.data) ? root.left : root.right;
return root;
}
}
class Solution:
def LCA(self, root, n1, n2):
while root and (root.data > max(n1.data, n2.data) or root.data < min(n1.data, n2.data)):
root = root.left if root.data > n1.data else root.right
return root
For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: Any Questions. Let’s make this learning journey more collaborative!
⭐ If you find this helpful, please give this repository a star! ⭐