跳转至

1644. 二叉树的最近公共祖先 II 🔒

难度中等

题目描述

给定一棵二叉树的根节点 root,返回给定节点 p 和 q 的最近公共祖先(LCA)节点。如果 p 或 q 之一 不存在 于该二叉树中,返回 null。树中的每个节点值都是互不相同的。

根据维基百科中对最近公共祖先节点的定义:“两个节点 p 和 q 在二叉树 T 中的最近公共祖先节点是 后代节点 中既包括 p 又包括 q 的最深节点(我们允许 一个节点为自身的一个后代节点 )”。一个节点 x 的 后代节点 是节点 x 到某一叶节点间的路径中的节点 y。

 

示例 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 = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 10
输出: null
解释: 节点 10 不存在于树中,所以返回 null。

 

提示:

  • 树中节点个数的范围是 [1, 104]
  • -109 <= Node.val <= 109
  • 所有节点的值 Node.val 互不相同
  • p != q

 

进阶: 在不检查节点是否存在的情况下,你可以遍历树找出最近公共祖先节点吗?

解法

方法一:递归(后序遍历)

思考

与普通 LCA 不同, \(p\) 或 \(q\) 可能不在树中,必须确认两者都出现才能返回祖先,否则返回空。

后序递归汇报子树是否包含目标:左右都包含,或一侧包含且当前结点本身是另一目标,则当前即为 LCA。

函数返回布尔「子树是否命中」,真正的答案写在外部变量 \(\textit{ans}\),避免把「找到一个点」误当成祖先。

我们设计一个函数 \(dfs(root, p, q)\),该函数返回以 \(root\) 为根节点的二叉树中是否包含节点 \(p\) 或节点 \(q\),如果包含,则返回 true,否则返回 false。

函数 \(dfs(root, p, q)\) 的递归过程如下:

如果当前节点 \(root\) 为空,则返回 false。

否则,我们递归地遍历左子树和右子树,得到 \(l\) 和 \(r\),分别表示左子树和右子树中是否包含节点 \(p\) 或节点 \(q\)。

如果 \(l\) 和 \(r\) 都为 true,说明当前节点 \(root\) 就是我们要找的最近公共祖先节点,将其赋值给变量 \(ans\)。

如果 \(l\) 或 \(r\) 为 true,并且当前节点 \(root\) 的值等于节点 \(p\) 或节点 \(q\) 的值,说明当前节点 \(root\) 就是我们要找的最近公共祖先节点,将其赋值给变量 \(ans\)。

最后,我们判断 \(l\) 或 \(r\) 是否为 true,或者当前节点 \(root\) 的值是否等于节点 \(p\) 或节点 \(q\) 的值,如果是,则返回 true,否则返回 false。

时间复杂度 \(O(n)\),空间复杂度 \(O(n)\)。其中 \(n\) 是二叉树的节点个数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None


class Solution:
    def lowestCommonAncestor(
        self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode'
    ) -> 'TreeNode':
        def dfs(root, p, q):
            if root is None:
                return False
            l = dfs(root.left, p, q)
            r = dfs(root.right, p, q)
            nonlocal ans
            if l and r:
                ans = root
            if (l or r) and (root.val == p.val or root.val == q.val):
                ans = root
            return l or r or root.val == p.val or root.val == q.val

        ans = None
        dfs(root, p, q)
        return ans
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private TreeNode ans;

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        dfs(root, p, q);
        return ans;
    }

    private boolean dfs(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {
            return false;
        }
        boolean l = dfs(root.left, p, q);
        boolean r = dfs(root.right, p, q);
        if (l && r) {
            ans = root;
        }
        if ((l || r) && (root.val == p.val || root.val == q.val)) {
            ans = root;
        }
        return l || r || root.val == p.val || root.val == q.val;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        dfs(root, p, q);
        return ans;
    }

private:
    TreeNode* ans = nullptr;

    bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (!root) {
            return false;
        }
        bool l = dfs(root->left, p, q);
        bool r = dfs(root->right, p, q);
        if (l && r) {
            ans = root;
        }
        if ((l || r) && (root->val == p->val || root->val == q->val)) {
            ans = root;
        }
        return l || r || root->val == p->val || root->val == q->val;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @param {TreeNode} p
 * @param {TreeNode} q
 * @return {TreeNode}
 */
var lowestCommonAncestor = function (root, p, q) {
    const dfs = root => {
        if (!root) {
            return false;
        }
        const l = dfs(root.left);
        const r = dfs(root.right);
        if (l && r) {
            ans = root;
        }
        if ((l || r) && (root.val === p.val || root.val === q.val)) {
            ans = root;
        }
        return l || r || root.val === p.val || root.val === q.val;
    };
    let ans = null;
    dfs(root);
    return ans;
};

评论