给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
解法1 暴力解法
思路
最简单的方法就是从根节点开始往下找 p
和 q
。并把路径上的节点记录下来,然后逐个比较是否相等。
代码
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 自底向上
思路
寻找离 p
和 q
最近、且在 p
和 q
之间的共同祖先。
假设目标节点是 x
,应该存在如下性质:p
在 x
的某个子树中,q
在 x
的另一个子树中,或者 x
本身就是 p
或 q
(例如一个节点是另一个节点的祖先)。
利用这个性质写出递归终止条件,接下来递归地去寻找左右子树,如果左右子树返回的结果都不为空,那么最近的公共祖先就是根节点。
代码
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)
栈空间调用