【剑指Offer】21、栈的压入、弹出序列
题目描述:
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
解题思路:
本题很直观的一个想法就是建立一个辅助栈,用该栈根据给出的序列来模拟压栈、弹栈动作,进而判断该序列是否可能正确。解决这样的问题一般不太好分析,可以通过几个具体的实例,使问题具体化,进而发现普遍规律。
以以下两个例子为例,我们可以找到判断一个序列是不是栈的弹出序列的规律:根据弹出序列,我们依次进行判断,如果下一个要弹出的数字刚好是栈顶数字,那么直接弹出;如果下一个要弹出的数字不在栈顶,则把压栈序列中还没有入栈的数字压入栈中,直到将下一个要弹出的数字压入栈顶为止,如果所有的数字都压入栈中后仍然没有找到下一个要弹出的数字,那么该序列就不可能是一个弹出序列。
举例:
编程实现(Java):
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
/*思路:模拟压栈和出栈过程
规律是:根据弹出序列,如果下一个弹出的元素正好是栈顶元素,则弹出;如果下一个弹出的数字不是栈顶元素,则将还未进栈的元素依次进栈,
直到找到要弹出的那个数字;最终,如果所有数字都压入栈中还没有找到弹出元素,则说明不是一个弹出序列
*/
if(pushA==null || popA==null)
return false;
Stack<Integer> stack=new Stack<>(); //辅助栈,用来模拟该过程
int p=0; //进栈序列下标
int len=pushA.length;
for(int i=0;i<popA.length;i++){
//当前需要弹出的是popA[i]
if(!stack.empty()&& stack.peek()==popA[i]) //弹出的元素正好是栈顶元素
stack.pop();
else{ //下一个弹出的数字不是栈顶元素
while(p<len && pushA[p]!=popA[i]){ //所有数字都压入栈中还没有找到弹出元素,则说明不是一个弹出序列
stack.push(pushA[p]);
p++;
}
p++;
}
}
return stack.isEmpty();
}
}
博学 审问 慎思 明辨 笃行