每日一題 - 劍指 Offer 68 - I. 二叉搜尋樹的最近公共祖先
阿新 • • 發佈:2020-07-18
題目資訊
-
時間: 2019-07-07
-
題目連結:Leetcode
-
tag:二叉樹 二叉搜尋樹 遞迴 迭代
-
難易程度:簡單
-
題目描述:
給定一個二叉搜尋樹, 找到該樹中兩個指定節點的最近公共祖先。
最近公共祖先的定義為:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示為一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”
例如,給定如下二叉搜尋樹: root = [6,2,8,0,4,7,9,null,null,3,5]
6 / \ 2 8 / \ / \ 0 4 7 9 / \ 3 5
示例1:
輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
輸出: 6
解釋: 節點 2 和節點 8 的最近公共祖先是 6。
示例2:
輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
輸出: 2
解釋: 節點 2 和節點 4 的最近公共祖先是 2, 因為根據定義最近公共祖先節點可以為節點本身。
注意
1. 所有節點的值都是唯一的。
2. p、q 為不同節點且均存在於給定的二叉搜尋樹中。
解題思路
本題難點
最近公共祖先
具體思路
祖先的定義: 若節點 p 在節點 root 的左(右)子樹中,或 p=root,則稱 root 是 p 的祖先。
最近公共祖先的定義: 設節點 root 為節點 p,q 的某公共祖先,若其左子節點 root.left 和右子節點 root.right 都不是 p,q 的公共祖先,則稱 root 是 “最近的公共祖先” 。
若 rootroo**t 是 p,qp,q 的 最近公共祖先 ,則只可能為以下情況之一:
- p 和 qq 在 root 的子樹中,且分列 root 的 異側(即分別在左、右子樹中);
- p=root,且 q在 root 的左或右子樹中;
- q=root,且 p 在 root的左或右子樹中;
本題給定了兩個重要條件:① 樹為 二叉搜尋樹 ,② 樹的所有節點的值都是 唯一 的。根據以上條件,可方便地判斷 p,q 與 root 的子樹關係,即:
- 若 root.val<p.val ,則 p 在 root右子樹 中
- 若 root.val>p.val ,則 p 在 root左子樹 中
- 若 root.val=p.val ,則 p 和root指向同一節點
提示 :迭代
程式碼
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while(root != null){
if(root.val > p.val && root.val > q.val){////當 p,q 都在 root 的 左子樹 中,則遍歷至 root.left
root = root.left;
}else if(root.val < p.val && root.val < q.val){//當 p,q 都在 root 的 右子樹 中,則遍歷至 root.right
root = root.right;
}else{
break;
}
}
return root;
}
}
複雜度分析:
- 時間複雜度 O(N) : 其中 N為二叉樹節點數;每迴圈一輪排除一層,二叉搜尋樹的層數最小為 logN(滿二叉樹),最大為 N(退化為連結串列)。
- 空間複雜度 O(1) :使用常數大小的額外空間。
其他優秀解答
解題思路
遞迴
- 當 p,q 都在 root 的 右子樹 中,則開啟遞迴 root.right 並返回;
- 否則,當 p,q 都在 root 的 左子樹 中,則開啟遞迴 root.left 並返回;
程式碼
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root.val < p.val && root.val < q.val)
return lowestCommonAncestor(root.right, p, q);
if(root.val > p.val && root.val > q.val)
return lowestCommonAncestor(root.left, p, q);
return root;
}
}