LeetCode 255. Verify Preorder Sequence in Binary Search Tree

Given an array of numbers, verify whether it is the correct preorder traversal sequence of a binary search tree.

You may assume each number in the sequence is unique.

Follow up:
Could you do it using only constant space complexity?

思路:
1. 根据性质,pre-order先中间、再左边、后右边,且:左边<中间<右边。recursive的方法。
2. 自己最开始想的是每次取subarray的第一个元素作为界限,后面的元素和这个界限比较,如果在某个位置开始一直大于这个界限,则把这个subarray分割成两部分,左边的一半是左子树,右边一半是右子树。然后分别对左子树和右子树做同样的操作,判断左右两半是否都是BST。复杂度worst case是o(n^2),average case是o(nlgn)。
3. 参考http://www.cnblogs.com/grandyang/p/5327635.html 有一种更好的recursive的方法,每次迭代更新lower bound 和upper bound。看数据是否在这个范围内。由于每个subarray都有上下两个限制,所以不用每一个level都遍历全部数据,复杂度worst case是o(n^2),average case是o(nlgn)。
4. o(n)的方法,iterative用stack实现,参考http://www.cnblogs.com/grandyang/p/5327635.html 思路:从左往右遍历array,遇到比stack top还小的元素,表明现在的数是top的数的left child,把这个数push到stack;遇到比stack top大的数,表明某节点的左子树遍历已经结束,需pop() stack top的数,并用stack top的值更新lower_bound,且后面遍历的所有数都必须大于这个lower_bound,这个比较、弹出、更新lower_bound的过程一直进行知道当前遍历的值小于stack top。
5. o(n)和o(nlgn)的方法,本质上区别是思维方法的不同。

o(nlgn)o(n)
把整个判断过程看成recursive的,用divide and conquer的方法, 把整个array分成两部分,对每一部分又分成更小的两部分,对 每一部分都判断从左往右遍历,根据当前遍历数的值和stack中值的大小关系, 判断得出后面所有遍历的数的lower_bound。 而是利用BST性质:左<根<右。如果遍历的值小于stack的top值, 表明这个数是位于top对应node的左子树;当遍历的值大于stack top值 ,表明这个数位于右子树,所以array这个数以及后面的所有数都 应该大于top,所以当前top的值就是lower_bound。
是分层的方法,一层判断完后更新边界后,进入更深的层次继续判断, 每个数都要访问lgn次不分层,而是不断更新lower_bound

6. 还可以不用stack,而是用给定的array来模拟这个stack,把array以及遍历过的位置用来存stack。空间o(1)

//方法1:recursive
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 higher){
    if(start>end) return true;
    int val=preorder[start];
    if(val<=lower||val>=higher) return false;
    int i=start+1;
    for(;i<=end;i++){
        if(preorder[i]>val) break;
    }
    return helper(preorder,start,i-1,lower,preorder[start])&&helper(preorder,i,end,preorder[start],higher);
}

//方法2:stack
bool verifyPreorder(vector<int>& preorder) {

    stack<int> ss;
    int lower_bound=INT_MIN;
    for(int i=0;i<preorder.size();i++){
        if(preorder[i]>=lower_bound) return false;
        if(ss.empty()||preorder[i]<ss.top()){//ss.empty()用于加保护,防止越界
            ss.push(preorder[i]);   
        }
        while(!ss.empty()&&preorder[i]>ss.top()){
            lower_bound=ss.top();
            ss.pop();   
        }
    }   
    return true;
}

//方法3:用给定的array已经访问过的部分模拟stack,节省空间
bool verifyPreorder(vector<int>& preorder) {


    int lower_bound=INT_MIN;
    int k=-1;
    for(int i=0;i<preorder.size();i++){
        if(preorder[i]>=lower_bound) return false;
        if(k>=0||preorder[i]<preorder[k]){
            preorder[++k]=preorder[i];  
        }
        while(k>=0&&preorder[i]>preorder[k]){
            lower_bound=preorder[k--];
        }
    }   
    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值