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

问题

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

示例

输入: [1,6,3,2,5]
输出: false

输入: [1,3,2,6,5]
输出: true

解答1:递归

class Solution {
public:
    vector<int> postorder;
    bool verifyPostorder(vector<int>& postorder) {
        this->postorder = postorder;
        return recur(0, postorder.size() - 1);
    }
    bool recur(int i, int j) {
        if (i > j - 2) return true; // 递归终止条件1
        int cur = i; // cur初始值为最左端
        while (postorder[cur] < postorder[j]) cur++;
        int m = cur; // m为右子树起点
        while (postorder[cur] > postorder[j]) cur++;// 检查右子树是否满足要求,cur!=j为递归终止条件2
        return cur == j && recur(i, m - 1) && recur(m, j - 1);
    }
};

重点思路

二叉搜索树的后序遍历特点为:假设遍历序列的长度为i,则最右端为根节点,从左到右遍历,设第一个大于根节点的位置为m,则[0, m-1]部分为左子树,[m, i - 2]部分为右子树。递归终止条件有两个,当遍历序列长度小于等于2时,必定符合要求;当右子树部分出现小于根节点的值时,必定不符合要求(在确定左子树时已经保证了那些值都小于根节点,所以只需要验证右子树就行)。

解答2:迭代(单调栈)

class Solution {
public:
    bool verifyPostorder(vector<int>& postorder) {
        stack<int> s;
        int parent = INT_MAX;
        for (int i = postorder.size() - 1; i >= 0; i--) {
            if (postorder[i] > parent) return false;
            while (!s.empty() && postorder[i] < s.top()) {
                parent = s.top();
                s.pop();
            }
            s.push(postorder[i]);
        }
        return true;
    }
};

重点思路

这里先说一下使用前中后序遍历验证二叉搜索树的做法。中序遍历最简单,只需要看遍历序列是不是严格单调递增就行;前序遍历使用递归和单调栈的做法很常见;而后序遍历的倒序是前序遍历的变种(根右左),同样也能使用单调栈。

这里说明前序遍历的单调栈做法。根据二叉搜索树的定义,左子树小于根节点。我们使用一个单调递减的单调栈,当遍历指向的元素大于栈顶值时,单调栈中存放的是该节点所有可能的根节点,栈中最后一个小于该节点的元素即其对应的根节点值。我们需要暂存这个根节点值,当这个根节点的右子树出现小于该暂存值的元素时,说明这不是二叉搜索树。

posted @ 2021-02-28 12:03  tmpUser  阅读(50)  评论(0编辑  收藏  举报