Description
Given two nodes of a binary tree p and q, return their lowest common ancestor (LCA).
Each node will have a reference to its parent node. The definition for Node is below:
class Node {
public int val;
public Node left;
public Node right;
public Node parent;
}
According to the definition of LCA on Wikipedia: “The lowest common ancestor of two nodes p and q in a tree T is the lowest node that has both p and q as descendants (where we allow a node to be a descendant of itself).”
Example 1:
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output: 3
Explanation: The LCA of nodes 5 and 1 is 3.
Example 2:
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Output: 5
Explanation: The LCA of nodes 5 and 4 is 5 since a node can be a descendant of itself according to the LCA definition.
Example 3:
Input: root = [1,2], p = 1, q = 2
Output: 1
Constraints:
The number of nodes in the tree is in the range [2, 10^5].
-10^9 <= Node.val <= 10^9
All Node.val are unique.
p != q
p and q exist in the tree.
Solution
Optimized
Find the height difference between p
and q
, and let the lower node go up height_diff
steps first, then both nodes go up. The first common node is their lowest common ancestor.
Time complexity:
o
(
log
n
)
o(\log n)
o(logn)
Space complexity:
o
(
1
)
o(1)
o(1)
Another way of coding this, let’s say p
is the lower node, when q
reaches the root, we can move q
to original p
, and when p
reaches the root, q
is height_diff
above the original p
, so we can move p
to original q
again, and now these 2 nodes move together.
Brute force
Find the ancestors of p
first, then find the ancestor of q
, if the node appears in p’s ancestors, then return.
Time complexity:
o
(
log
n
)
o(\log n)
o(logn)
Space complexity:
o
(
n
)
o(n)
o(n)
Code
Optimized
"""
# Definition for a Node.
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
self.parent = None
"""
class Solution:
def lowestCommonAncestor(self, p: 'Node', q: 'Node') -> 'Node':
n1, n2 = p, q
diff = 0
while n1 or n2:
if n1 and n2:
n1 = n1.parent
n2 = n2.parent
elif n1:
n1 = n1.parent
diff -= 1
elif n2:
n2 = n2.parent
diff += 1
while diff < 0:
p = p.parent
diff += 1
while diff > 0:
q = q.parent
diff -= 1
while p != q:
p = p.parent
q = q.parent
return p
Another way of coding:
"""
# Definition for a Node.
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
self.parent = None
"""
class Solution:
def lowestCommonAncestor(self, p: 'Node', q: 'Node') -> 'Node':
n1, n2 = p, q
while n1 != n2:
n1 = n1.parent if n1 else q
n2 = n2.parent if n2 else p
return n1
Brute Force
"""
# Definition for a Node.
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
self.parent = None
"""
class Solution:
def lowestCommonAncestor(self, p: 'Node', q: 'Node') -> 'Node':
p_ans = []
while p:
p_ans.append(p)
p = p.parent
while q:
if q in p_ans:
return q
q = q.parent