Discover how a simple recursive trick can save hours of confusing ancestor hunting!
Why Lowest Common Ancestor in Binary Tree in DSA C++?
Imagine you have a family tree on paper and you want to find the closest common grandparent of two cousins. You try to trace each cousin's ancestors manually, comparing each step. It quickly becomes confusing and slow as the tree grows.
Manually checking each ancestor for two nodes means retracing many paths repeatedly. It is easy to make mistakes, miss a common ancestor, or waste time going up and down the tree multiple times.
The Lowest Common Ancestor (LCA) method lets you find the closest shared ancestor of two nodes in a binary tree efficiently. It uses a simple recursive approach to explore the tree once and find the answer without repeated work.
bool isAncestor(Node* root, Node* target) {
if (!root) return false;
if (root == target) return true;
return isAncestor(root->left, target) || isAncestor(root->right, target);
}
Node* findLCA(Node* root, Node* node1, Node* node2) {
if (!root) return nullptr;
if (root == node1 || root == node2) return root;
if (isAncestor(root->left, node1) && isAncestor(root->left, node2))
return findLCA(root->left, node1, node2);
if (isAncestor(root->right, node1) && isAncestor(root->right, node2))
return findLCA(root->right, node1, node2);
return root;
}Node* findLCA(Node* root, Node* node1, Node* node2) {
if (!root) return nullptr;
if (root == node1 || root == node2) return root;
Node* leftLCA = findLCA(root->left, node1, node2);
Node* rightLCA = findLCA(root->right, node1, node2);
if (leftLCA && rightLCA) return root;
return leftLCA ? leftLCA : rightLCA;
}This concept enables quick and reliable discovery of the closest shared ancestor in any binary tree, unlocking efficient tree analysis and queries.
In a company's organizational chart, finding the lowest common manager of two employees helps understand reporting lines and collaboration paths.
Manual ancestor checks are slow and error-prone.
LCA uses recursion to find the closest shared ancestor efficiently.
It simplifies complex tree queries in many real-world scenarios.
Practice
Solution
Step 1: Understand the definition of LCA
The Lowest Common Ancestor is the deepest node in the tree that has both given nodes as descendants (a node can be a descendant of itself).Step 2: Differentiate from other nodes
It is not necessarily the root or the node with smallest value, but the common ancestor closest to the two nodes.Final Answer:
The deepest node that is an ancestor of both nodes -> Option AQuick Check:
LCA = deepest common ancestor [OK]
- Confusing LCA with root node
- Choosing node by value instead of position
- Thinking LCA is the first visited node in traversal
Solution
Step 1: Analyze parameter types
The function should accept a pointer to the root node and two integer values representing node keys.Step 2: Analyze return type
The function returns a pointer to the TreeNode representing the LCA, so return type must be TreeNode*.Final Answer:
TreeNode* findLCA(TreeNode* root, int n1, int n2); -> Option BQuick Check:
Function signature with pointers and correct return type [OK]
- Using value instead of pointer for root
- Returning int instead of TreeNode*
- Passing root by value causing copy
#include <iostream>
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
TreeNode* findLCA(TreeNode* root, int n1, int n2) {
if (!root) return nullptr;
if (root->val == n1 || root->val == n2) return root;
TreeNode* left = findLCA(root->left, n1, n2);
TreeNode* right = findLCA(root->right, n1, n2);
if (left && right) return root;
return left ? left : right;
}
int main() {
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);
TreeNode* lca = findLCA(root, 6, 2);
std::cout << lca->val << std::endl;
return 0;
}Solution
Step 1: Trace the tree structure and nodes
Nodes 6 and 2 are both children of node 5 in the tree.Step 2: Apply LCA logic
Since 5 is the lowest node that has both 6 and 2 as descendants, the function returns node 5.Final Answer:
5 -> Option DQuick Check:
LCA(6,2) = 5 [OK]
- Choosing root 3 instead of node 5
- Confusing child nodes as LCA
- Returning one of the input nodes incorrectly
TreeNode* findLCA(TreeNode* root, int n1, int n2) {
if (!root) return nullptr;
if (root->val == n1 || root->val == n2) return root;
TreeNode* left = findLCA(root->left, n1, n2);
TreeNode* right = findLCA(root->right, n1, n2);
if (left && right) return root;
if (left) return right;
return right;
}Solution
Step 1: Analyze the return statements
The code incorrectly returns 'right' when 'left' is true, which is wrong logic.Step 2: Correct the return for left subtree
It should return 'left' when 'left' is true and 'right' is false to propagate the found node correctly.Final Answer:
Change 'if (left) return right;' to 'if (left) return left;' -> Option CQuick Check:
Return correct subtree pointer [OK]
- Returning wrong subtree pointer
- Ignoring nullptr checks
- Changing return type unnecessarily
Solution
Step 1: Understand the problem with duplicate values
If nodes have duplicate values, comparing values is ambiguous and can lead to wrong LCA.Step 2: Use pointer comparison
Comparing node pointers directly ensures the exact nodes are identified regardless of value duplicates.Step 3: Modify function accordingly
The LCA function should check if the current node pointer equals either of the target node pointers.Final Answer:
Modify the LCA function to compare node pointers directly instead of values -> Option AQuick Check:
Compare pointers, not values, for duplicates [OK]
- Using values for comparison with duplicates
- Assuming tree is BST to fix duplicates
- Sorting nodes which is unnecessary
Ready to prove it?
Pass the test and this pattern moves unknown
