二叉搜索树的最近公共祖先:最直观的想法是,二叉搜索树的特点是左子树数值<中间节点数值<右子树数值,那么我们可以根据这一特性来遍历二叉搜索树,分别得到从根节点到节点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<q,则p和q的最近公共祖先一定在区间[p,q]中。上述我们遍历了两次二叉树,其实我们可以优化为只遍历一次二叉树。lowestCommonAncestor函数指的是在以root为根的二叉搜索树中遍历p和q的最近公共祖先,其可以分为如下几种情况:一是如果当前节点值比p和q均大则遍历当前节点的左子树,在以左子树为根的二叉搜索树中遍历p和q的最近公共祖先;二是如果当前节点值比p和q均小则遍历当前节点的右子树,在以右子树为根的二叉搜索树中遍历p和q的最近公共祖先;反之则最近公共祖先即为当前节点值,注意,由于该函数包含返回值,故一旦返回值有值则直接返回。

// 在以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;
}