总结【剑指Offer】二叉搜索树的后序遍历序列

二叉搜索树的后序遍历序列

https://www.nowcoder.com/practice/a861533d45854474ac791d90e447bafd?tpId=13&tqId=11176&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking

一、递归法

1.分析:一次遍历确定出左右子树的分界点,然后再分别对两棵子树进行递归判断。
2.代码

    bool IsBST(const vector<int>& sequence, const int start, const int end){
        if (start>=end) return true;  // 可能出现start>end的情况

        int pivot;
        for (pivot=start; sequence[pivot]<sequence[end]; ++pivot);  // 查找分界点
        for (int i=pivot; i<=end; ++i)
            if (sequence[i]<sequence[end]) return false;
        return IsBST(sequence, start, pivot-1) && IsBST(sequence, pivot, end-1);
    }

    bool VerifySquenceOfBST_1(vector<int> sequence) {
        if (!sequence.size()) return false;
        return IsBST(sequence, 0, sequence.size()-1);
    }

3.复杂度
时间复杂度:O(n*lgn)
空间复杂度:O(lgn)

二、直接法

1.分析:BST的中序遍历是有序的,所以将后序序列排序后可以得到BST的中序遍历序列,然后看这两个序列是否可以构建一颗二叉树
2.代码

    bool BuildTree(const vector<int>& in, const vector<int>& post){
        if (in.size()!=post.size()) return false;  // 非法情况,提前退出
        if (in.size()==0 || in.size()==1 && in[0]==post[0]) return true; // 递归出口
        // 在中序序列中查找root位置,确定左右子树位置
        vector<int>::const_iterator pos_in=find(in.begin(), in.end(), post.back());
        if (pos_in==in.end()) return false;
        int i=pos_in-in.begin(), j=in.end()-pos_in;

        vector<int> left_in(in.begin(), pos_in), left_post(post.begin(), post.begin()+i);
        vector<int> right_in(pos_in+1, in.end()), right_post(post.begin()+i, post.end()-1);
        return BuildTree(left_in, left_post) && BuildTree(right_in, right_post);
    }

    bool VerifySquenceOfBST_2(vector<int> sequence) {
        if (!sequence.size()) return false;
        vector<int> inOrder(sequence.begin(), sequence.end());
        sort(inOrder.begin(), inOrder.end());  // 构建辅助中序序列
        return BuildTree(inOrder, sequence);
    }

3.复杂度
时间复杂度:O(2n*lgn)
空间复杂度:O(n)

三、上下界约束法

1.分析:BST的特征是左<根<右(这个特点确定唯一的中序序列),后序遍历的顺序是左右根,基于此,当从后向前遍历后序序列时, 先遍历到根,然后遍历到大于根的结点则向右(并把未向左的结点压入栈中),最后遇到小于根的结点则向左(之后序列中的结点值不能大于此结点)。
2.代码

    bool VerifySquenceOfBST(vector<int> sequence) {
        if (!sequence.size()) return false;
        stack<int> min;
        int max=0x7fffffff;
        min.push(sequence.back());

        for (int i=sequence.size()-1; i>=0; --i){
            if (sequence[i]>max) return false;
            if (min.empty() || sequence[i]>min.top()) min.push(sequence[i]); //向右
            while (!min.empty() && sequence[i]<min.top()) {
                max = min.top();
                min.pop();
            } // 退栈,向左
        }
        return true;
    }

3.复杂度
时间复杂度:O(n)
空间复杂度:O(n)

全部评论
老哥,第三种方法当sequence[i]
2 回复 分享
发布于 2020-05-11 10:53
2楼说的好像有道理,比如输入以下用例:1,3,2,7,5,6,9,8,4;这不是一棵二叉搜索树,但是代码会返回true。如果有出栈操作,在其结束后放入sequence[i]结果就正确了
1 回复 分享
发布于 2020-06-09 22:35
大神,能再详细讲讲第三种方法的思路吗,看文字解释没看明白啊
点赞 回复 分享
发布于 2020-03-16 20:29

相关推荐

不愿透露姓名的神秘牛友
10-05 10:13
已编辑
HHHHaos:让这些老登来现在秋招一下,简历都过不去
点赞 评论 收藏
分享
评论
8
3
分享
牛客网
牛客企业服务