Problem Description
Given the root of a binary tree and an array of TreeNode objects, return the lowest common ancestor (LCA) of all the nodes in the array. A node can be a descendant of itself. All target nodes are guaranteed to be present in the tree and each node value is unique.
Key Insights
- Use a Depth-First Search (DFS) traversal to explore the tree.
- Keep track of how many target nodes are found in the subtree rooted at the current node.
- For each node, sum up the number of target nodes found in the left subtree, right subtree, and the current node.
- The first (deepest) node in the postorder DFS traversal that reports the total count equal to the number of target nodes is the LCA.
- Using a HashSet to store the target nodes (or their values) allows O(1) membership checks during traversal.
Space and Time Complexity
Time Complexity: O(n) - We visit each node in the tree once. Space Complexity: O(h) - The recursion stack can grow up to the height of the tree (worst-case O(n) in a skewed tree).
Solution
We solve the problem using a DFS traversal. The idea is to traverse the tree and for each node, count the number of targets present in its left subtree, right subtree, and if the current node itself is a target. When the cumulative count equals the total number of targets and if the LCA has not been found yet, we set the current node as the LCA.
The DFS function returns to its caller the number of target nodes found in the subtree rooted at the current node. Because the DFS recursion is postorder (children processed before the current node), the first time we get a complete match (i.e. all target nodes found) corresponds to the deepest such node, which is by definition the lowest common ancestor.
Data structures used:
- A set (or hash table) for fast look-up of the target nodes.
- Recursive call stack to implement DFS.