🛠️ Settings
Problem Statement
Given the root of a binary tree and two nodes p
and q
return the lowest common ancestor (LCA)
of these two nodes.
The lowest common ancestor
is defined as the lowest node in the tree that has both p
and q
as descendants (where we allow a node to be a descendant of itself).
Examples
Example 1:
Input: p = 5, q = 1
3
/ \
5 1
/ \ / \
6 2 0 8
/ \
7 4
Output: 3
Explanation: The Lowest Common Ancestor of node 5 and 1 is 3 as it is the lowest node in the tree that has both 5 and 1 as descendants.
Example 2:
Input: p = 5, q = 4
3
/ \
5 1
/ \ / \
6 2 0 8
/ \
7 4
Output: 5
Explanation:
The Lowest Common Ancestor of nodes 5 and 4 is 5, as 5 is an ancestor of 4.
Example 3:
Input: p = 1, q = 2
1
/
2
Output: 1
Explanation:
The Lowest Common Ancestor of nodes 1 and nodes 2 is 1, as 1 is the root and has 2 as a descendant.
Different Approaches
1️⃣ Depth First Search
Intuition:
Approach:
We solve this using Depth-First-Search (DFS) and recursion. The goal is to traverse the tree and identify where the two nodes p
and q
split in the subtree.
- If the current node is null, return null.
- If the current node matches either
p
orq
, return the current node. - Recursively find
p
andq
in the left and right subtrees.- If one node is found in the left subtree and the other in the right subtree, the current node is their LCA.
- If both nodes are found in one subtree, return the subtree's result.
- If neither node is found, return null.
Code:
#include <bits/stdc++.h>
using namespace std;
struct TreeNode {
int data;
TreeNode* left;
TreeNode* right;
TreeNode(int val) : data(val), left(NULL), right(NULL) {}
};
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
// Base case
if (root == NULL || root == p || root == q) {
return root;
}
// Search in left and right subtrees
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
// Result
if (left == NULL) {
return right;
} else if (right == NULL) {
return left;
} else { // Both left and right are not null, we found our result
return root;
}
}
};
int main() {
// Construct a simple binary tree
TreeNode* root = new TreeNode(3);
root->left = new TreeNode(5);
root->right = new TreeNode(1);
root->left->left = new TreeNode(6);
root->left->right = new TreeNode(2);
root->right->left = new TreeNode(0);
root->right->right = new TreeNode(8);
Solution solution;
TreeNode* p = root->left; // Node with value 5
TreeNode* q = root->right; // Node with value 1
TreeNode* lca = solution.lowestCommonAncestor(root, p, q);
cout << "Lowest Common Ancestor: " << lca->data << endl;
return 0;
}
Complexity Analysis:
- Time complexity:
O(N)
where n is the number of nodes. - Space complexity: O(N), auxiliary space.