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

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

題目資訊

  • 時間: 2019-07-07

  • 題目連結:Leetcode

  • tag:二叉樹 遞迴 深度優先搜尋

  • 難易程度:中等

  • 題目描述:

    給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。

    百度百科中最近公共祖先的定義為:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示為一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”

    例如,給定如下二叉樹: root = [3,5,1,6,2,0,8,null,null,7,4]

           3
         /   \
        5     1
       / \   / \
      6   2 0   8
         / \
        7   4
    

示例1:

輸入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
輸出: 3
解釋: 節點 5 和節點 1 的最近公共祖先是節點 3。

示例2:

輸入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
輸出: 5
解釋: 節點 5 和節點 4 的最近公共祖先是節點 5。因為根據定義最近公共祖先節點可以為節點本身。

注意

1. 所有節點的值都是唯一的。
2. p、q 為不同節點且均存在於給定的二叉樹中。

解題思路

本題難點

一般二叉樹查詢最近公共祖先節點。

具體思路

考慮通過遞迴對二叉樹進行後序遍歷,當遇到節點 p 或 q 時返回。從底至頂回溯,當節點 p,q 在節點 root 的異側時,節點 root 即為最近公共祖先,則向上返回 root 。

遞推工作

  • 遞迴左子節點,返回值記為 left ;
  • 遞迴右子節點,返回值記為 right ;

返回值

  • 當 left 和 right 同時為空 :說明 root 的左 / 右子樹中都不包含 p,q ,返回 null ;
  • 當 left 和 right 同時不為空 :說明 p,q 分列在 root 的 異側 (分別在 左 / 右子樹),因此 root 為最近公共祖先,返回 root ;
  • left 為空right 不為空 :p,q 都不在 root 的左子樹中,直接返回 right 。具體可分為兩種情況:
    1. p,q 其中一個在 root的 右子樹 中,此時 right 指向 p(假設為 p );
    2. p,q 兩節點都在 root 的 右子樹 中,此時的 right 指向 最近公共祖先節點
  • left 不為空right為空 :p,q 都不在 root 的右子樹中,直接返回 left 。具體可分為兩種情況
    1. p,q 其中一個在 root的 左子樹 中,此時 left 指向 p(假設為 p );
    2. p,q 兩節點都在 root 的 左子樹 中,此時的 left 指向 最近公共祖先節點

提示

程式碼

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
      //當 root 等於 p,q ,則直接返回 root
        if(root == null || root.val == p.val || root.val == q.val){
            return root;
        }
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        if(left == null){
            return right;
        }
        if(right == null){
            return left;
        }
        return root;
    }
}

複雜度分析:

  • 時間複雜度 O(N) : 其中 N為二叉樹節點數;最差情況下,需要遞迴遍歷樹的所有節點。
  • 空間複雜度 O(N) : 最差情況下,遞迴深度達到 N,系統使用 O(N)大小的額外空間。