1. 程式人生 > 實用技巧 >每日一題 - 劍指 Offer 68 - I. 二叉搜尋樹的最近公共祖先

每日一題 - 劍指 Offer 68 - I. 二叉搜尋樹的最近公共祖先

題目資訊

  • 時間: 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最近公共祖先 ,則只可能為以下情況之一:

  1. p 和 qq 在 root 的子樹中,且分列 root 的 異側(即分別在左、右子樹中);
  2. p=root,且 q在 root 的左或右子樹中;
  3. 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為二叉樹節點數;每迴圈一輪排除一層,二叉搜尋樹的層數最小為 log⁡N(滿二叉樹),最大為 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;
    }
}