49.二叉树的最近公共祖先

6 阅读1分钟

题目链接

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

解法1 暴力解法

思路

最简单的方法就是从根节点开始往下找 pq 。并把路径上的节点记录下来,然后逐个比较是否相等。

代码

function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
    const findPath = (node, target, path) => {
        if (!node) return false;

        path.push(node);
        if (node === target) return true;

        if (findPath(node.left, target, path) || findPath(node.right, target, path)) {
            return true;
        }

        path.pop();
        return false;
    };

    const pathP = [];
    const pathQ = [];
    findPath(root, p, pathP);
    findPath(root, q, pathQ);

    let i = 0;                                    // 要找最近的祖先
    while (i < pathP.length && i < pathQ.length && pathP[i] === pathQ[i]) {
        i++;
    }
    return pathP[i - 1] || null;
};

时空复杂度

时间复杂度:O(n) 两遍遍历

空间复杂度:O(n) 好的情况下存储树高量级的节点,最坏全部

解法2 自底向上

思路

寻找离 pq 最近、且在 pq 之间的共同祖先。

假设目标节点是 x,应该存在如下性质:px 的某个子树中,qx 的另一个子树中,或者 x 本身就是 pq(例如一个节点是另一个节点的祖先)。

利用这个性质写出递归终止条件,接下来递归地去寻找左右子树,如果左右子树返回的结果都不为空,那么最近的公共祖先就是根节点。

代码

function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
    if (!root || root === p || root === q) {
        return root;
    }

    const left = lowestCommonAncestor(root.left, p, q);
    const right = lowestCommonAncestor(root.right, p, q);

    if (left && right) {
        return root;
    }
    return left || right;
};

时空复杂度

时间复杂度:O(n)

空间复杂度:O(h) 栈空间调用