leetcode题解236:二叉树的最近公共祖先
一、题目内容
题目要求找到给定二叉树中两个指定节点的最近公共祖先。最近公共祖先的定义为:对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
二、题目分析
输入和输出
-
输入:一个二叉树的根节点 root,以及两个指定节点 p 和 q。
-
输出:一个二叉树节点,表示 p 和 q 的最近公共祖先。
递归函数 lowestCommonAncestor 的逻辑
-
基本情况:
-
如果当前节点为空(root == NULL),返回 NULL。
-
如果当前节点是 p 或 q,返回当前节点。
-
-
递归检查左子树和右子树:
-
递归调用 lowestCommonAncestor(root->left, p, q),检查左子树中是否存在 p 或 q。
-
递归调用 lowestCommonAncestor(root->right, p, q),检查右子树中是否存在 p 或 q。
-
-
返回结果:
-
如果左子树和右子树的返回值都不为空,说明 p 和 q 分别在当前节点的左子树和右子树中,当前节点即为最近公共祖先。
-
如果左子树的返回值不为空,右子树的返回值为空,说明 p 和 q 都在左子树中,返回左子树的返回值。
-
如果左子树的返回值为空,右子树的返回值不为空,说明 p 和 q 都在右子树中,返回右子树的返回值。
-
如果左子树和右子树的返回值都为空,说明当前子树中不存在 p 和 q,返回 NULL。
-
三、解题要点
1. 二叉树的定义
二叉树是一种特殊的树形数据结构,每个节点最多有两个子节点,通常分为左子节点和右子节点。二叉树的结构使得递归方法成为解决许多问题的自然选择。
2. 最近公共祖先的性质
最近公共祖先(LCA)是指在二叉树中,两个节点 p 和 q 的最近公共祖先 x 满足以下条件:
-
x 是 p 和 q 的祖先(一个节点也可以是它自己的祖先)。
-
x 的深度尽可能大,即 x 是最接近 p 和 q 的祖先。
3.解题思路
-
基本情况:
-
如果当前节点为空(
root == NULL
),返回NULL
。因为空树中不存在任何节点,自然也没有公共祖先。 -
如果当前节点是 p 或 q(
root == p || root == q
),返回当前节点。因为当前节点本身就是 p 或 q,它可能是最近公共祖先,或者至少是 p 或 q 的祖先。
-
-
递归检查左子树和右子树:
-
递归调用
lowestCommonAncestor(root->left, p, q)
,检查左子树中是否存在 p 或 q。 -
递归调用
lowestCommonAncestor(root->right, p, q)
,检查右子树中是否存在 p 或 q。
-
-
返回结果:
-
如果左子树的返回值不为空,且右子树的返回值也不为空(
left != NULL && right != NULL
),说明 p 和 q 分别在当前节点的左子树和右子树中,当前节点即为最近公共祖先,返回当前节点。 -
如果左子树的返回值不为空,但右子树的返回值为空(
left != NULL && right == NULL
),说明 p 和 q 都在左子树中,返回左子树的返回值。 -
如果左子树的返回值为空,但右子树的返回值不为空(
left == NULL && right != NULL
),说明 p 和 q 都在右子树中,返回右子树的返回值。 -
如果左子树和右子树的返回值都为空(
left == NULL && right == NULL
),说明当前子树中不存在 p 和 q,返回NULL
。 -
如果左子树或右子树的递归调用返回了非空值,说明在该子树中找到了 p 或 q,或者找到了它们的公共祖先。
-
如果左子树和右子树的递归调用都返回了非空值,说明当前节点是 p 和 q 的最近公共祖先。
-
四、代码解答
class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {// 如果当前节点为空,返回 NULLif (root == NULL) return root;// 如果当前节点是 p 或 q,返回当前节点if (root == q || root == p) return root;// 递归检查左子树TreeNode* left = lowestCommonAncestor(root->left, p, q);// 递归检查右子树TreeNode* right = lowestCommonAncestor(root->right, p, q);// 如果左子树和右子树的返回值都不为空,当前节点即为最近公共祖先if (left != NULL && right != NULL) {return root;}// 如果左子树的返回值不为空,右子树的返回值为空,返回左子树的返回值if (left != NULL && right == NULL) {return left;}// 如果左子树的返回值为空,右子树的返回值不为空,返回右子树的返回值if (left == NULL && right != NULL) {return right;}// 如果左子树和右子树的返回值都为空,返回 NULLreturn NULL;}
};
详细注释
-
成员函数
lowestCommonAncestor
:主函数,用于递归查找两个指定节点的最近公共祖先。 -
递归函数
lowestCommonAncestor
:-
基本情况:如果当前节点为空,返回 NULL。
-
递归检查左子树:递归调用
lowestCommonAncestor(root->left, p, q)
,检查左子树中是否存在 p 或 q。 -
递归检查右子树:递归调用
lowestCommonAncestor(root->right, p, q)
,检查右子树中是否存在 p 或 q。 -
返回结果:根据左子树和右子树的返回值判断当前节点是否为最近公共祖先。
-
回溯和递归的详细解释
-
递归:递归是一种函数调用自身的方法,用于解决复杂问题。在本题中,递归用于逐层检查每个节点是否为 p 或 q 的祖先。
-
终止条件:递归的终止条件是当前节点为空。
-
回溯:在递归调用返回后,通过返回值恢复到当前节点的状态,确保每次递归返回后,状态正确,不会影响后续的递归调用。