栈的输出队列

题目描述

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

我的看法:
一个比较直观的方法就是,用一个辅助栈模拟弹出栈的过程。
比如说,顺序压入序列一时,当栈顶元素为4时,则弹出4,接着压入5,此时与辅助栈栈顶元素5相同,则弹出5。没有元素可压时,按照上述条件,一次处理,直到为空。这样就可以确定结果了。
代码:

    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        if(pushV.size()==0 || popV.size()==0)   return false;
        int index = 0;
        int j = 0;
        stack<int> s;
        while(index != pushV.size()){
            s.push(pushV[index]);
            ++index;

            while(!s.empty() && popV[j] == s.top() ){
                ++j;
                s.pop();
            }
        }
        while(!s.empty() && popV[j] == s.top() ) {
            ++j;
            s.pop();
        }
        return s.empty();
    }

然而,有没有更好的方法呢?
这里的讨论是基于序列的下标,为了便于讨论,从1开始。
假如有 个数入栈,下标为1,2,3
那么输出序列有:

1 2 3
1 3 2
2 1 3
2 3 1
3 2 1

然而,3 1 2 却是不可以的。
同理,还可以模拟一下4 个数入栈的结果,你会发现
3 1 ……
4 2 ……
等序列是不可以的。
因为当 3 弹出的时候,后面跟着的是2 1
发现规律没有。

  • 当序列递增时,ok
  • 当序列递减时,且相差为1 ,ok
  • 当序列递减时,且相差大于1,但后续序列都递减时,ok
  • 当序列递减时,且相差大于1,但后续序列非严格递减时,no

那么总结如下:
直到序列递减大于1时,如果后续序列严格递减,则ok,否则no。其他情况都ok。

那问题又来了,假如我想输出所有的出栈序列呢?
很明显,先对下标进行全排列,然后去除不符合以上条件的序列即可。
那怎么生成全排列?嗯,自己查算法。
另外一个方法就是使用递归。
详见参考资料。
代码如下:

void playStack(int a[], int index, int len ,vector<int>& stk, vector<int>& que)
{
    if(index == len)
    {
        for_each(que.begin(), que.end(), [](int i)
        {
            cout<<i<<"  ";
        });
        for(int i = stk.size()-1;i>=0;--i)
            cout<<stk[i]<<"  ";
        cout<<endl;
        return;
    }

    stk.push_back(a[index]);
    playStack(a, index+1, len, stk, que);

    stk.pop_back();
    if(!stk.empty())
    {
        que.push_back(stk.back());
        stk.pop_back();
        playStack(a, index, len, stk, que);
        stk.push_back(que.back());
        que.pop_back();
    }
}

void play(int a[], int len)
{
    vector<int> stk;
    vector<int> que;
    playStack(a, 0, len, stk, que);
}

参考资料:
给一串数字,输出所有的出栈序列 - lzshlzsh的专栏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值