1. 程式人生 > 其它 >236 二叉樹的最近公共祖先(遞迴)

236 二叉樹的最近公共祖先(遞迴)

1. 問題描述:

給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。百度百科中最近公共祖先的定義為:“對於有根樹 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 均存在於給定的二叉樹中

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree

2. 思路分析:

這道題目與力扣中的235題是類似的,235題為二叉搜尋樹所以通過p,q節點與當前根節點的大小關係判斷p,q節點與根節點的相對位置,但是這道題目為二叉樹所以不能夠通過p,q節點與根節點的關係來判斷屬於哪一種情況所以我們需要遍歷整棵樹,遍歷的時候找到對應的p,q節點的位置,我們可以定義一個變數state來記錄p,q節點查詢的情況,可以將state看成是兩位二進位制來表示p,q節點尋找的情況,第一位二進位制表示節點q的尋找情況,第二位二進位制表示節點p的尋找情況,二進位制的1表示已經找到當前的節點。我們其實在遞迴完當前的左子樹的時候判斷當前的根節點是否等於p或者q(相當於是前序遍歷的順序)如果是p節點那麼與1進行或運算即可,如果為q那麼與2進行或運算即可。遞迴完左子樹將結果儲存在state中,然後遞迴右子樹,並且state與右子樹遞迴的結果進行或運算即可,最後判斷當前的state是否等於3,如果未為3說明二進位制的兩個位置上為1那麼找到了p,q節點,我們可以宣告一個全域性變數res來記錄第一次同時找到p,q節點的最近公共祖先。

3. 程式碼如下:

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    res = None

    # 使用二進位制來表示是否找到了p, q節點, 第一位表示是否有q, 第二位表示是否有p
    def dfs(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root: return 0
        state = self.dfs(root.left, p, q)
        if root == p:
            # 找到了p節點
            state |= 1
        elif root == q:
            # 找到了q節點
            state |= 2
        state |= self.dfs(root.right, p, q)
        # 找到了p,q節點而且當前的節點是第一次出現的節點
        if state == 3 and not self.res: self.res = root
        return state

    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        self.dfs(root, p, q)
        return self.res