Lowest Common Ancestor in Binary Tree in DSA C# - Time & Space Complexity
We want to understand how the time needed to find the lowest common ancestor grows as the tree gets bigger.
How does the search through the tree change when it has more nodes?
Analyze the time complexity of the following code snippet.
public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) {
return root;
}
TreeNode left = LowestCommonAncestor(root.left, p, q);
TreeNode right = LowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
return root;
}
return left ?? right;
}
This code finds the lowest common ancestor of two nodes in a binary tree by searching both sides recursively.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive calls visiting each node once.
- How many times: Each node is checked once during the recursion.
As the tree grows, the function visits every node once to find the answer.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 node visits |
| 100 | About 100 node visits |
| 1000 | About 1000 node visits |
Pattern observation: The number of operations grows directly with the number of nodes.
Time Complexity: O(n)
This means the time to find the lowest common ancestor grows linearly with the number of nodes in the tree.
[X] Wrong: "The function only searches part of the tree, so it runs faster than visiting all nodes."
[OK] Correct: The function may need to check every node in the worst case, especially if the nodes are deep or spread out.
Understanding this time complexity helps you explain how your solution scales and shows you know how recursion explores trees efficiently.
"What if the tree was a binary search tree and you used its properties? How would the time complexity change?"
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: Identify the correct description
Among the options, only the deepest common ancestor fits this definition.Final Answer:
The deepest node that is an ancestor of both nodes -> Option DQuick Check:
LCA = deepest common ancestor [OK]
- Confusing LCA with root node
- Thinking LCA is the smaller value node
- Assuming LCA is a child of both nodes
TreeNode?Solution
Step 1: Analyze method parameters and return type
The method should accept the root node and two nodes to find LCA for, and return a TreeNode representing the LCA.Step 2: Match signature with correct types
public TreeNode FindLCA(TreeNode root, TreeNode p, TreeNode q) correctly uses TreeNode for all nodes and returns TreeNode. Other options have incorrect parameter types or return types.Final Answer:
public TreeNode FindLCA(TreeNode root, TreeNode p, TreeNode q) -> Option AQuick Check:
Correct signature uses TreeNode parameters and return type [OK]
- Using int instead of TreeNode for nodes
- Wrong return type (void or int)
- Incorrect access modifier or parameter order
FindLCA(root, node5, node1).val?
3 / \ 5 1 / \ / \ 6 2 0 8 / \ 7 4 // Code snippet: TreeNode lca = FindLCA(root, node5, node1); Console.WriteLine(lca.val);
Solution
Step 1: Locate nodes 5 and 1 in the tree
Node 5 is left child of root 3, node 1 is right child of root 3.Step 2: Find lowest common ancestor
The root node 3 is the lowest node that has both 5 and 1 as descendants.Final Answer:
3 -> Option BQuick Check:
LCA(5,1) = 3 [OK]
- Choosing one of the nodes instead of their ancestor
- Confusing node values with LCA
- Ignoring tree structure
public TreeNode FindLCA(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) return null;
if (root == p || root == q) return root;
TreeNode left = FindLCA(root.left, p, q);
TreeNode right = FindLCA(root.right, p, q);
if (left != null && right != null) return root;
return left != null ? left : right;
}Solution
Step 1: Review base cases and recursive calls
The method returns null if root is null, returns root if root matches p or q, then recursively searches left and right subtrees.Step 2: Check logic for combining results
If both left and right are non-null, root is LCA; else returns whichever subtree found a node. This is correct logic.Final Answer:
No bug, method is correct -> Option CQuick Check:
Standard LCA recursive method is correct [OK]
- Comparing node values instead of references if nodes are unique
- Missing base case for null root
- Incorrect return logic
Solution
Step 1: Understand the problem with non-unique values
Since values are not unique, we cannot rely on node references or values alone to find LCA directly.Step 2: Use path comparison approach
Find paths from root to each node value (may find multiple nodes), then compare paths to find the last common node, which is the LCA.Final Answer:
Use a method that finds paths from root to each node value and then compare paths to find LCA -> Option AQuick Check:
Path comparison works for non-unique values [OK]
- Assuming node references are unique
- Returning root always
- Using hash set without paths
Ready to prove it?
Pass the test and this pattern moves unknown
