思路:
如果能够自底向上查找元素,就能找到公共祖先了
回溯啊:回溯就是天然的自底向上查找元素。
而后序遍历就是天然的回溯过程:因为后序遍历先处理的一定是叶子节点,
接下来就是逻辑处理过程,
1,如果一个节点的左为p(q),右为q(p),那这个节点一定是最近的祖先。
2,如果走到左树的节点(p)为null,而右树(q)找到节点,此时,祖先(q)一定为右节点,p在q的左右子树里面,q为最近祖先
3,如果两个节点都为空,说明没有公共祖先
递归三部曲:
1,确定递归函数返回值以及参数
需要递归函数告诉我们,是否找到了这个节点,但我们最后要返回节点,所以需要返回找到的当前节点,如果返回值为null,说明没找到
TreeNode*left=lowestCommonAncestor(root->left,p,q);
2,确定终止条件
如果找到了节点p或者q或者走到nullptr,直接返回
if(root==p||root==q||root==nullptr)return root
3,确定递归单层逻辑
值得注意的是 本题函数有返回值,是因为回溯的过程需要递归函数的返回值做判断,但本题我们依然要遍历树的所有节点。
递归函数有返回值就是要遍历某一条边,但有返回值也要看如何处理返回值!
搜索一条边的写法
if(递归函数(root->left))return ;
if(递归函数(root->right))return ;
搜索一颗树的写法
left = 递归函数(root->left);
right = 递归函数(root->right);
left与right的逻辑处理;
在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。
逻辑处理:
//处理逻辑
if(left!=nullptr&&right!=nullptr)return root;
if(left==nullptr&&right!=nullptr)
return right;
else if(left!=nullptr&&right==nullptr)
return left;
else return nullptr;
代码:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
if(root==p||root==q||root==nullptr)return root;
//递归查找左右节点
TreeNode*left=lowestCommonAncestor(root->left,p,q);
TreeNode*right=lowestCommonAncestor(root->right,p,q);
//处理逻辑
if(left!=nullptr&&right!=nullptr)return root;
if(left==nullptr&&right!=nullptr)
return right;
else if(left!=nullptr&&right==nullptr)
return left;
else return nullptr;
}
};