1.问题描述
已知从1到n编号的n个元素按照从小到大的顺序依次入栈,每个数字入栈后即可出栈,也可在栈中停留,等待后面的数字入栈出栈后再出栈。请设计一个函数用来检验某个给定的出栈序列是否合法。
例如,当n=4时,4321为合法出栈序列,而4132为非法出栈序列。
2.分析
如果这不是一个要求编程的问题,而是笔试题的话。那么是否为合法出栈序列是非常好判断的,只需要牢记一个规则:将入栈元素按入栈顺序由1到n进行编号,凡是合法的出栈序列,每个数后面的比它小的数,必然是按递减次序排列的。所以4132是非法的,因为4后面的比它小的数字不是按照递减次序排列的。
现在我们需要设计一个函数来检验某个给定的出栈序列是否合法,那么这个规律是否能适用呢?理论上是可行的,然而这个方法无论是从时间复杂度上还是从编码难度上看都没有以下方法好。
这里更好的方法就是对整个出入栈的过程进行模拟。我们先假定给定的出栈序列是合法的且将出栈序列压入到一个队列当中。然后开始模拟入栈操作(即按照从1到n的次序入栈),当某个元素入栈后如果其编号等于队头元素编号则说明此元素应当进行出栈操作同时还要进行出队操作。如果到最后栈为空,则说明该出栈序列是合法的,否则为非法。
3.实现
具体代码如下:
#include <queue>
#include <stack>
using namespace std;
//队列q中由队头至对尾顺序存放给定出栈序列
bool checkValidOrder(queue<int> &q)
{
stack<int> s; //模拟栈
int n = q.size();
for(int i = 1; i <= n; i++)
{
s.push(i); //元素入栈
//栈非空且栈顶元素等于队头元素,说明该元素需要出栈
while(!s.empty() && s.top() == q.front())
{
s.pop(); q.pop();
}
}
//栈为空说明出栈序列合法,否则非法
return s.empty() ? true : false;
}