剑指Offer(二十一)——栈的压入、弹出序列
题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
题目分析:
判断出栈顺序是否为入栈顺序的一种出栈情况,我们可以用一个栈去模拟进出情况。
模拟方法:
根据入栈顺序和出栈顺序的第一个元素确定,第一次何时出栈。第一次出栈后栈中都省了哪些元素。
在继续入栈,根据出栈舒顺序的第二个元素确定,第二次合适出栈,第二次出栈后都剩了什么。
……
知道所有的元素都入栈完毕,此时是第j次出栈完,因为不会再入栈了,所以栈剩下所有元素依次出栈的顺序就是 出栈数组j之后的顺序。
链接:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106?answerType=1&f=discussion
来源:牛客网
举例:
入栈1,2,3,4,5
出栈4,5,3,2,1
首先1入辅助栈,此时栈顶1≠4,继续入栈2
此时栈顶2≠4,继续入栈3
此时栈顶3≠4,继续入栈4
此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3
此时栈顶3≠5,继续入栈5
此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3
来源:牛客网
举例:
入栈1,2,3,4,5
出栈4,5,3,2,1
首先1入辅助栈,此时栈顶1≠4,继续入栈2
此时栈顶2≠4,继续入栈3
此时栈顶3≠4,继续入栈4
此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3
此时栈顶3≠5,继续入栈5
此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3
用图解释一下:
123直接入栈,4入了又出,不必入栈。

5也是入了又出,此时入栈顺序遍历完,栈中剩下321,正好对应出栈顺序5之后的元素
1 伪代码: 2 3 int j=0; 4 5 for(int i=0;i<入栈顺序大小;i++) { 6 7 if(入栈元素i==出栈元素j) { 8 9 入了又出,不用加到模拟栈中; 10 11 j++;//再出就是下一个了 12 13 } 14 15 else { 16 17 入栈元素不是出栈元素,说明被压住了,存到模拟栈中; 18 19 } 20 21 } 22 23 此时入栈顺序遍历完,j是下一个要出的元素,之后的顺序要和模拟栈中元素一致。 24 25 for(;j<出栈顺序大小;j++) { 26 27 if(出栈元素j 不等于 栈顶 ){ 28 29 有错误return false; 30 31 } 32 33 若相等,就模拟栈出栈,判断下一个 34 35 } 36 37 //出栈遍历完,没有问题 38 39 return true;
附上本人代码和运行结果:
#include<stack> class Solution { public: bool IsPopOrder(vector<int> pushV,vector<int> popV) { int j=0; for(int i = 0;i<pushV.size();i++) { if(pushV[i] == popV[j]) { j++; } else { sck.push(pushV[i]); } } //入栈顺序完 for(;j<popV.size();j++) { if(popV[j] != sck.top()) { return false; } sck.pop(); } return true; } private: stack<int> sck; };
解决方法性能分析:两个单独的for时间复杂度n+n,o(n);空间上用了辅助栈o(n)。
对于代码的简洁性,简单优化了一下,运行时间由5ms变成4ms。
#include<stack> class Solution { public: bool IsPopOrder(vector<int> pushV,vector<int> popV) { int j=0; for(int i = 0;i<pushV.size();i++) { if(pushV[i] == popV[j]) j++; else sck.push(pushV[i]); } //入栈顺序完 for(;j<popV.size() && popV[j] == sck.top();j++) sck.pop(); return sck.empty(); } private: stack<int> sck; };
如有疏漏,欢迎指正。