题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列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);
}