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

题目描述

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

题目来源:牛客网

算法分析

算法其实很简单,利用后序遍历的特性,根节点是在最后面的,那么我们找到了根节点之后,利用左子树的所有节点必定是小于它,右子树的所有节点必定是大于它的,可以将前面的数组分成两部分,两部分再递归操作就行了~

举个栗子

对于这个二叉搜索树:

它后序遍历的序列为[1, 4, 3, 6, 9, 8, 5],首先找到最后一个元素5,为整棵树的根节点,然后从前往后找,看看有没有第一个比5大的节点在哪,找到是6,于是将数组分成两部分:1)左子树[1, 4, 3];2)右子树[6, 9, 8]。注意这个问题是要求检验这个序列是否可能为后序遍历的序列,所以需要看看左子树的所有节点是否都小于根节点,同时所有右子树的节点是否都大于根节点。通过检查之后,再递归,分别对左子树、右子树进行是否可能为二叉搜索树后序遍历的序列的判断。

What’s More

原来题目的测试样例是错的(我发了纠错建议,不知道现在改过来了没),空树也是二叉树,所以输入空序列,应该输出true才对。
下面是(我觉得应该是)正确的写法,最后面是牛客网那种测试方法的写法:

class Solution {
public:
    bool VerifySquenceOfBST(vector<int> seq) {
        if (seq.empty())
            return true;

        int mid = findMiddle(seq), tail = seq.size() - 1;
        // 检查左子树是否有大于根节点的情况
        // 其实在计算mid的时候已经保证了左边这部分必定是小于根节点的
        // 即这个循环只是用来示意需要关注这个性质是否成立而已,实际上是多余的
        for (int i = 0; i < mid; ++i)
            if (seq[i] > seq[tail])
                return false;
        // 检查右子树是否有小于根节点的情况
        for (int i = mid; i < tail; ++i)
            if (seq[i] < seq[tail])
                return false;

        bool left = VerifySquenceOfBST(vector<int>(seq.begin(), seq.begin()+mid));
        bool right = VerifySquenceOfBST(vector<int>(seq.begin()+mid, seq.begin()+tail));
        // 其实这里还可以利用&&的短路性质来加速判断,不必像上面这样写
        // 直接写return left && Verify....
        // 这样如果left为false的话,就可以直接少掉对右子树的判断了
        return left && right;
    }

    int findMiddle(const vector<int>& seq) {
        int tail = seq.size() - 1, key = seq[tail];
        for (int i = 0; i < tail; ++i)
            if (seq[i] > key)
                return i;
        return tail;
    }
};

对于(我觉得是错误的)样例测试:

class Solution {
public:
    bool VerifySquenceOfBST(vector<int> seq) {
        if (seq.empty())
            return false;

        if (seq.size() == 1)
            return true;

        int mid = findMiddle(seq), tail = seq.size() - 1;
        // 检查左子树是否有大于根节点的情况
        for (int i = 0; i < mid; ++i)
            if (seq[i] > seq[tail])
                return false;
        // 检查右子树是否有小于根节点的情况
        for (int i = mid; i < tail; ++i)
            if (seq[i] < seq[tail])
                return false;

        // 如果左子树为空或右子树为空,只需查找一边
        if (mid == 0 || mid == tail)
            return VerifySquenceOfBST(vector<int>(seq.begin(), seq.begin()+tail));
        bool left = VerifySquenceOfBST(vector<int>(seq.begin(), seq.begin()+mid));
        bool right = VerifySquenceOfBST(vector<int>(seq.begin()+mid, seq.begin()+tail));
        return left && right;
    }

    int findMiddle(const vector<int>& seq) {
        int tail = seq.size() - 1, key = seq[tail];
        for (int i = 0; i < tail; ++i)
            if (seq[i] > key)
                return i;
        return tail;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值