Description
給定一棵二元搜尋樹 (BST) 和兩個節點 p、q,找到它們的最低共同祖先 (LCA)。LCA 定義為同時是 p 和 q 祖先的最深節點。
Example:
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 Output: 6
Intuition#
利用 BST 性質:若 p 和 q 分別在當前節點的兩側,當前節點就是 LCA。
- BST 中左子樹所有值 < 根 < 右子樹所有值
- 若 p、q 都小於根,LCA 在左子樹;都大於根,LCA 在右子樹;否則當前節點就是 LCA
Approaches#
1: Recursive#
- 概念: 根據 BST 性質遞迴搜尋
- 時間複雜度:
O(h),h 為樹高 - 空間複雜度:
O(h),遞迴堆疊
class Solution {
fun lowestCommonAncestor(root: TreeNode?, p: TreeNode?, q: TreeNode?): TreeNode? {
if (root == null || p == null || q == null) return null
if (p.`val` < root.`val` && q.`val` < root.`val`) {
return lowestCommonAncestor(root.left, p, q)
}
if (p.`val` > root.`val` && q.`val` > root.`val`) {
return lowestCommonAncestor(root.right, p, q)
}
return root
}
}⭐ 2: Iterative#
- 概念: 同樣利用 BST 性質,但用迴圈代替遞迴,節省堆疊空間
- 時間複雜度:
O(h) - 空間複雜度:
O(1)
class Solution {
fun lowestCommonAncestor(root: TreeNode?, p: TreeNode?, q: TreeNode?): TreeNode? {
var current = root
while (current != null) {
if (p!!.`val` < current.`val` && q!!.`val` < current.`val`) {
current = current.left
} else if (p.`val` > current.`val` && q!!.`val` > current.`val`) {
current = current.right
} else {
return current
}
}
return null
}
}🔑 Takeaways#
- Pattern: 利用 BST 有序性質做二分搜尋式的遍歷
- 關鍵技巧: BST 的 LCA 不需要回溯,只需要沿著樹向下走,比一般二元樹的 LCA 簡單得多