236. Lowest Common Ancestor of a Binary Tree
/**
* 寻找二叉树中两个节点的最近公共祖先
* @param {TreeNode} root - 二叉树的根节点
* @param {TreeNode} p - 目标节点1
* @param {TreeNode} q - 目标节点2
* @returns {TreeNode} 最近公共祖先节点
*/
function lowestCommonAncestor(root, p, q) {
// 递归终止条件:
// 1. 遍历到空节点(说明当前路径没有找到p/q)
// 2. 找到p节点或q节点(直接返回该节点,作为找到的标记)
if (root === null || root === p || root === q) {
return root
}
// 递归遍历左子树,寻找p或q
const left = lowestCommonAncestor(root.left, p, q)
// 递归遍历右子树,寻找p或q
const right = lowestCommonAncestor(root.right, p, q)
// 情况1:左子树和右子树都没找到p/q,说明当前节点的子树中无目标节点,返回null
if (left === null && right === null) {
return null
}
// 情况3:左子树没找到,右子树找到了,说明p/q都在右子树中,返回右子树找到的节点
if (left === null) {
return right
}
// 情况4:右子树没找到,左子树找到了,说明p/q都在左子树中,返回左子树找到的节点
if (right === null) {
return left
}
// 情况2:左子树和右子树都找到了目标节点(一个在左、一个在右)
// 说明当前root就是最近公共祖先,返回root
return root
}问:lowestCommonAncestor 函数的返回值是什么意思?
答:返回值的准确含义是「最近公共祖先的候选项」。对于最外层的递归调用者来说,返回值是最近公共祖先的意思。但是,在递归过程中,返回值可能是最近公共祖先,也可能是空节点(表示子树内没找到任何有用信息)、节点 p 或者节点 q(可能成为最近公共祖先,或者用来辅助判断上面的某个节点是否为最近公共祖先)。
作者:灵茶山艾府 链接:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/solutions/2023872/fen-lei-tao-lun-luan-ru-ma-yi-ge-shi-pin-2r95/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
根据以上定义,若 root 是 p,q 的 最近公共祖先 ,则只可能为以下情况之一:
- p 和 q 在 root 的子树中,且分列 root 的 异侧(即分别在左、右子树中);
- p=root ,且 q 在 root 的左或右子树中;
- q=root ,且 p 在 root 的左或右子树中;
二叉树最近公共祖先——递归解析
思路
通过递归对二叉树进行先序遍历,当遇到节点 p 或 q 时返回。从底至顶回溯,当 p, q 在当前节点 root 的异侧时,root 即为最近公共祖先,向上返回 root。
1. 终止条件
- 当越过叶节点
- 当
root == null时,直接返回null
- 当
- 找到目标节点
- 当
root == p或root == q时,直接返回root
- 当
2. 递推工作
- 递归调用左子树,返回值记为
left - 递归调用右子树,返回值记为
right
3. 根据 left 和 right 的情况返回结果
left和right同时为空- 说明
root的左右子树都不包含p, q - 返回
null
- 说明
left和right同时不为空- 说明
p, q分别在root的左、右子树 - 因此当前
root就是最近公共祖先,返回root
- 说明
left为空,right不为空- 说明
p, q不在root的左子树中,直接返回right - 细分两种情况:
- 只有
p或q(假设为p)在右子树,此时right指向p p, q都在右子树,此时right指向它们的最近公共祖先
- 只有
- 说明
left不为空,right为空- 同理,说明
p, q都不在右子树,直接返回left
- 同理,说明
作者:Krahets 链接:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/solutions/240096/236-er-cha-shu-de-zui-jin-gong-gong-zu-xian-hou-xu/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
# 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':
# 只要当前根节点是p和q中的任意一个,就返回(因为不能比这个更深了,再深p和q中的一个就没了)
if not root or root == p or root == q:
return root
# 根节点不是p和q中的任意一个,那么就继续分别往左子树和右子树找p和q
# left和right为 p 或者 q 或者 None
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
# p和q都没找到,那就没有
if left == None and right == None:
return None
# 左子树没有p也没有q,就返回右子树的结果
if left == None:
return right
# 右子树没有p也没有q就返回左子树的结果
if right == None:
return left
# 左右子树都找到p和q了,那就说明p和q分别在左右两个子树上,所以此时的最近公共祖先就是root
return root