|
| 1 | +# 236. Lowest Common Ancestor of a Binary Tree |
| 2 | + |
| 3 | +## Recursive Solution |
| 4 | + |
| 5 | +- Runtime: O(N) |
| 6 | +- Space: O(H) |
| 7 | +- N = Number of nodes in tree |
| 8 | +- H = Height of tree |
| 9 | + |
| 10 | +From the perspective of a root node, there are only three options to consider. |
| 11 | +- The LCA exists on the left sub-tree. |
| 12 | +- The LCA exists on the right sub-tree. |
| 13 | +- The LCA is the root node. |
| 14 | + |
| 15 | +To figure out if an LCA exists would mean we need to find p and q in either sub-tree. |
| 16 | +If either are found, we have to let the parent know of their existence. |
| 17 | + |
| 18 | +The other question is when to evaluate these conditions. |
| 19 | +We generally don't want to traverse a sub-tree if the LCA is already found, so if the recursion function returns the LCA, we should instead return it back up the tree. |
| 20 | +Secondly, if LCA has not been found from either side, we need to know if either p or q were found. |
| 21 | +So a number would be returned to the parent node. |
| 22 | +With this number, we can check if our root is p or q and add it with the returned number found. |
| 23 | +If the number happens to be 2, we found the LCA. |
| 24 | +In summary, we need a post-order traversal recursion call. |
| 25 | + |
| 26 | +The worst case is that we have to traverse the entire tree to find p and q. However, we will never need more than height of the tree O(H) space to find p or q. |
| 27 | + |
| 28 | +``` |
| 29 | +from collections import namedtuple |
| 30 | +
|
| 31 | +LCA = namedtuple('LCA', ['n_found', 'lca']) |
| 32 | +
|
| 33 | +class Solution: |
| 34 | + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': |
| 35 | +
|
| 36 | + def LCA_helper(root): |
| 37 | + if root is None: |
| 38 | + return LCA(n_found=0, lca=None) |
| 39 | + left = LCA_helper(root.left) |
| 40 | + if left.n_found == 2: |
| 41 | + return left |
| 42 | + right = LCA_helper(root.right) |
| 43 | + if right.n_found == 2: |
| 44 | + return right |
| 45 | + n_found = left.n_found + right.n_found + (1 if root is p or root is q else 0) |
| 46 | + return LCA(n_found=n_found, lca=root if n_found == 2 else None) |
| 47 | +
|
| 48 | + return LCA_helper(root).lca |
| 49 | +``` |
0 commit comments