1. 程式人生 > 其它 >236. 二叉樹的最近公共祖先【DFS】

236. 二叉樹的最近公共祖先【DFS】

題目描述

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

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

示例 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 。因為根據定義最近公共祖先節點可以為節點本身。

示例 3:

輸入:root = [1,2], p = 1, q = 2
輸出:1

提示:

樹中節點數目在範圍 [2, 10^5] 內。
-10^9 <= Node.val <= 10^9
所有 Node.val 互不相同 。
p != q
p 和 q 均存在於給定的二叉樹中。

解題思路

我們遞迴遍歷整棵二叉樹,定義 fx 表示 x 節點的子樹中是否包含 p 節點或 q 節點,如果包含為 true,否則為 false。那麼符合條件的最近公共祖先 x 一定滿足如下條件:
( f l s o n & & f r s o n ) ∣ ∣ ( ( x = p ∣ ∣ x = q ) & & ( f l s o n ∣ ∣ f r s o n ) ) (f_{lson} \&\& f_{rson}) || ((x = p || x = q) \&\& (f_{lson} || f_{rson}))

(flson&&frson)((x=px=q)&&(flsonfrson))

其中 lson 和 rson 分別代表 x 節點的左孩子和右孩子。初看可能會感覺條件判斷有點複雜,我們來一條條看, f l s o n & & f r s o n f_{lson} \&\& f_{rson} flson&&frson說明左子樹和右子樹均包含 p 節點或 q 節點,如果左子樹包含的是 p 節點,那麼右子樹只能包含 q 節點,反之亦然,因為 p 節點和 q 節點都是不同且唯一的節點,因此如果滿足這個判斷條件即可說明 x 就是我們要找的最近公共祖先。再來看第二條判斷條件,這個判斷條件即是考慮了 x 恰好是 p 節點或 q 節點且它的左子樹或右子樹有一個包含了另一個節點的情況,因此如果滿足這個判斷條件亦可說明 x 就是我們要找的最近公共祖先。

你可能會疑惑這樣找出來的公共祖先深度是否是最大的。其實是最大的,因為我們是自底向上從葉子節點開始更新的,所以在所有滿足條件的公共祖先中一定是深度最大的祖先先被訪問到,且由於 fx 本身的定義很巧妙,在找到最近公共祖先 x 以後,fx 按定義被設定為 true ,即假定了這個子樹中只有一個 p 節點或 q 節點,因此其他公共祖先不會再被判斷為符合條件。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    TreeNode ans;
    boolean dfs(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) return false;
        boolean lson = dfs(root.left, p, q);
        boolean rson = dfs(root.right, p, q);
        if ((lson && rson) || ((root.val == q.val || root.val == p.val) && (lson || rson))) {
            ans = root;
        }
        return lson || rson || root.val == q.val || root.val == p.val;
    }
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        dfs(root,p,q);
        return ans;
    }
}