Solution)
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# Base Case
if not root or root == p or root == q:
return root
# Recursive Call
l = self.lowestCommonAncestor(root.left, p, q)
r = self.lowestCommonAncestor(root.right, p, q)
# If p and q are descendants of a certain node
# return that node
if l and r:
return root
# If p or q is an ancestor of the other
# return that ancestor
return l or r
Problem: LeetCode
Reference: Marlen09
Time Complexity: O(h^2)
Space Complexity: O(1)
Explanation)
There are 2 patterns of finding the lowest common ancestor.
1) Both p and q are descendants of a certain node
2) One of the nodes is the ancestor of the other
This solution's main goal is to distinguish which pattern is given and return the lowest common ancestor according to the pattern.
1. Base Case)
This base case looks a bit complicated but it's just shortened efficiently.
If there is no root, we return None.
If root is p, we return p.
If root is q, we return q.
It's just these 3 conditions, but written in a clever way.
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 1. Base Case
if not root or root == p or root == q:
return root
2. Find p and q in left and right subtrees)
These recursions are used for us to find p and q in left/right subtrees.
This recursion will give us two results.
1) We get values for both l and r
2) We only get result of either l or r
Essentially, the result of l and r will let us know which pattern of ancestry is used.
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 1. Base Case
if not root or root == p or root == q:
return root
# 2. Find p and q in left and right subtrees
l = self.lowestCommonAncestor(root.left, p, q)
r = self.lowestCommonAncestor(root.right, p, q)
3. Distinguish the pattern)
As I said the result of l and r will allow us to distinguish the pattern of ancestry.
1) If we get values for both l and r, that means there is a certain node that has both p and q as its descendants.
2) If we get one of the values of either l or r, that means that variable with a value is the ancestor ot the other.
Return the node according to the result.
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 1. Base Case
if not root or root == p or root == q:
return root
# 2. Find p and q in left and right subtrees
l = self.lowestCommonAncestor(root.left, p, q)
r = self.lowestCommonAncestor(root.right, p, q)
# 3. Distinguish the pattern
if l and r:
return root
return l or r
It's amazing this user came up with such concise and clever solution. I thought about having 2 patterns of ancestry, but I didn't know how to code it. Amazing solution!
'[LeetCode] > [Medium]' 카테고리의 다른 글
[Top Interview 150] 102. Binary Tree Level Order Traversal (0) | 2023.09.19 |
---|---|
[Top Interview 150] 199. Binary Tree Right Side View (0) | 2023.09.15 |
[Top Interview 150] 173. Binary Search Tree Iterator (0) | 2023.09.13 |
[Top Interview 150] 129. Sum Root to Leaf Numbers (0) | 2023.09.08 |
[Top Interview 150] 114. Flatten Binary Tree to Linked List (0) | 2023.09.07 |