二叉树的最近公共祖先
Tips
题目类型: Tree
题目
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先.
最近公共祖先的定义为: "对于有根树 T 的两个节点 p 和 q, 最近公共祖先表示为一个节点 x, 满足 x 是 p 和 q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先).
示例
3
/ \
5 1
/ \ / \
6 2 0 8
/ \
7 4
输入: p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3
输入: p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5, 因为根据定义最近公共祖先节点可以为节点本身
题解
递归函数的定义
本题为 LCA(最近公共祖先) 的经典算法, git 里的 merge
其实就是利用了该算法.
- 如果 left 和 right 都不为空, 则说明 p 和 q 分别在 root 的左右子树中, 因此 root 就是它们的最近公共祖先, 返回 root.
- 如果 left 不为空, 而 right 为空, 则说明 p 和 q 都在 root 的左子树中, 返回 left.
- 如果 right 不为空, 而 left 为空, 则说明 p 和 q 都在 root 的右子树中, 返回 right.
- 如果 left 和 right 都为空, 则说明 p 和 q 在以 root 为根的子树中都不存在, 返回 null.
对于上面的代码, 因为我们使用的后序遍历, 即从下往上走, 因此递归结束的返回值, 也就是离 p, q 最近的了.
/**
* 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) {
if (!root) return null
if (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 ? left : right
}
- 时间复杂度:
O(n)
, 其中n
是二叉树的节点数. 最坏情况下, 需要遍历所有节点. - 空间复杂度:
O(h)
, 其中h
是二叉树的高度. 最坏情况下, 树退化成链表,h = n
, 空间复杂度为O(n)
. 最好情况下, 树为完全二叉树,h = logn
, 空间复杂度为O(logn)
.