leetcode:255 验证前序遍历序列二叉搜索树

题目来源

题目描述

给定一个整数数组,你需要验证它是否是一个二叉搜索树正确的先序遍历序列。
你可以假定该序列中的数都是不相同的。

参考以下这颗二叉搜索树:

在这里插入图片描述

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

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

题目解析

思路

  • 二叉搜索树的特点是: 左子树的值 < 根节点的值 < 右子树的值
  • 所以其中序遍历一定是有序数组,但是前序遍历有什么规律呢?其前序遍历的数组是局部递减,整体递增的数组
  • 所以可以借助单调栈
    • 先设一个最小值 low,然后遍历数组,如果当前值小于这个最小值 low,返回 false
    • 对于根节点,将其压入栈中,然后往后遍历
      • 如果遇到的数字比栈顶元素小,说明是其左子树的点,继续压入栈中
      • 直到遇到的数字比栈顶元素大,那么就是右边的值了。需要找到是哪个节点的右子树,所以更新 low 值并删掉栈顶元素,然后继续和下一个栈顶元素比较,如果还是大于,则继续更新 low 值和删掉栈顶,直到栈为空或者当前栈顶元素大于当前值停止,压入当前值
    • 这样如果遍历完整个数组之前都没有返回 false 的话,最后返回 true 即可

在这里插入图片描述

class Solution {
public:
    bool verifyPreorder(vector<int>& preorder) {
        if(preorder.size() <= 2) return true;
        int MIN = INT32_MIN;
        stack<int> s;
        for(int i = 0; i < preorder.size(); ++i)
        {
            if(preorder[i] < MIN)
                return false;
            while(!s.empty() && s.top() < preorder[i])//遇到大的了,右分支
            {
                MIN = s.top();//记录弹栈的栈顶为最小值
                s.pop();
            }
            s.push(preorder[i]);
        }
        return true;
    }
};

进阶要求

为了使空间复杂度为常量,我们不能使用 stack,所以直接修改 preorder,将 low 值存在 preorder 的特定位置即可

class Solution {
public:
    bool verifyPreorder(vector<int>& preorder) {
        int low = INT_MIN, i = -1;
        for (auto a : preorder) {
            if (a < low) return false;
            while (i >= 0 && a > preorder[i]) {
                low = preorder[i--];
            }
            preorder[++i] = a;
        }
        return true;
    }
};

分治法

  • 在递归函数中维护一个下界 lower 和上界 upper,那么当前遍历到的节点必须在(low, upper)之间
  • 然后在给定区间内搜索第一个>=当前值的点,以此为分界点,左右两边分别调用递归函数。注意左半部分的 upper 更新为当前节点值 val,表明左子树的节点值都必须小于当前节点值,而右半部分的递归的 lower 更新为当前节点值 val,表明右子树的节点值都必须大于当前节点值
  • 如果左右两部分的返回结果均为真,则整体返回真
class Solution {
public:
    bool verifyPreorder(vector<int>& preorder) {
        return helper(preorder, 0, preorder.size() - 1, INT_MIN, INT_MAX);
    }
    bool helper(vector<int>& preorder, int start, int end, int lower, int upper) {
        if (start > end) return true;
        int val = preorder[start], i = 0;
        if (val <= lower || val >= upper) return false;
        for (i = start + 1; i <= end; ++i) {
            if (preorder[i] >= val) break;
        }
        return helper(preorder, start + 1, i - 1, lower, val) && helper(preorder, i, end, val, upper);
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值