【剑指offer-C++】JZ68:二叉搜索树的最近公共祖先

【剑指offer-C++】JZ68:二叉搜索树的最近公共祖先

    • 题目描述
    • 解题思路

题目描述

描述:给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

1.对于该题的最近的公共祖先定义:对于有根树T的两个节点p、q,最近公共祖先LCA(T,p,q)表示一个节点x,满足x是p和q的祖先且x的深度尽可能大。在这里,一个节点也可以是它自己的祖先。
2.二叉搜索树是若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值。
3.所有节点的值都是唯一的。
4.p、q 为不同节点且均存在于给定的二叉搜索树中。

数据范围:

3<=节点总数<=10000,0<=节点值<=10000。

如果给定以下搜索二叉树: {7,1,12,0,4,11,14,#,#,3,5},如下图:

【剑指offer-C++】JZ68:二叉搜索树的最近公共祖先_第1张图片

输入:{7,1,12,0,4,11,14,#,#,3,5},1,12
返回值:7
说明:节点1 和 节点12的最近公共祖先是7  
输入:{7,1,12,0,4,11,14,#,#,3,5},12,11
返回值:12
说明:因为一个节点也可以是它自己的祖先.所以输出12 

解题思路

二叉搜索树的最近公共祖先:最直观的想法是,二叉搜索树的特点是左子树数值<中间节点数值<右子树数值,那么我们可以根据这一特性来遍历二叉搜索树,分别得到从根节点到节点p的路径数组pathp以及从根节点到节点q的路径数组pathq,然后遍历两个数组得到最后一个相同的节点值,其即为二叉搜索树的最近公共祖先。遍历路径具体实现方法如下:首先将当前值加入路径数组,然后比较当前值和目标值,如果当前值大于目标值,则在当前节点的左子树寻找目标值,反之如果当前值小于目标值,则在当前节点的右子树寻找目标值,当找到当前目标值即返回,注意,是先加入再返回这样的顺序喔!

vector<int> pathp;
vector<int> pathq;
// 二叉搜索树:左<<右
void traverse(TreeNode* cur, int target, vector<int>& path)
{
    // 加入到数组
    path.push_back(cur->val);
    // 找到目标值
    if(cur->val==target)
       return;
    // 当前小于目标则在右子树
    if(cur->val<target)
       traverse(cur->right, target,path);
    // 当前大于目标则在左子树
    else if(cur->val>target)
       traverse(cur->left,target,path);
}
int lowestCommonAncestor(TreeNode* root, int p, int q) 
{
    // 记录结果
    int res;
    // 找到从根节点到p的路径
    traverse(root, p, pathp);
    // 找到从根节点到q的路径
    traverse(root, q, pathq);
    // 找到最后一个相同的节点值
    for(int i=0,j=0;i<pathp.size()&&j<pathq.size();i++,j++)
    {
       if(pathp[i]==pathq[j])
         res=pathp[i];
    }
    return res;
}

优化:既然我们知道二叉搜索树的特性是左子树数值<中间节点数值<右子树数值,那么两个节点假设p

// 在以root为根的二叉搜索树中遍历p和q的最近公共祖先
int lowestCommonAncestor(TreeNode* root, int p, int q) 
{
    // 题目中说了树不为空 节点值唯一 故这里可以不处理边界条件
    // 记录结果 节点值在0~10000之间 
    int left=-1,right=-1;
    // 当前节点值比p和q均大则遍历当前节点的左子树
    if(root->val>p&&root->val>q)
    {
        left=lowestCommonAncestor(root->left, p, q);
        if(left!=-1)
        return left;
    }    
    // 当前节点值比p和q均小则遍历当前节点的右子树
    if(root->val<p&&root->val<q)
    {
        right=lowestCommonAncestor(root->right, p, q);
        if(right!=-1)
        return right;
    }
    // 否则当前节点值在两者之间返回当前值 其包含p是q祖先或者q是p祖先的情况 就可以减少判断
    return root->val;
}

你可能感兴趣的:(剑指offer,c++,算法,数据结构)