1、题目描述
【JZ21】输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
知识点:栈
难度:☆
2、解题思路
本题的意思是说:已知一个入栈序列,入栈顺序和序列的顺序已知,问另一个序列的顺序是否可能的出栈顺序。例如,已知一个入栈序列为{1,2,3,4}
,操作顺序是:入栈、入栈、入栈、出栈、入栈、出栈、出栈、出栈。那么此时的出栈顺序为{3,4,2,1}
。即序列{3,4,2,1}
是{1,2,3,4}
的可能的弹出顺序。
题意要求判断对于一个给定入栈顺序的序列,判断另一个序列是否为它的可能出栈序列。
以下PushA
为入栈序列,PopA
为出栈序列。
根据栈的先进后出原则,如果入栈序列是全部入栈后再出栈,那么我们只需要判断两个序列是否顺序相反即可,但现在的情况是,在入栈过程中可能有些元素会在中间出栈,因此,我们不能简单判断序列顺序相反,而是要遍历两个序列,一步步检查是否符合要求。
先假设PopA
就是PushA
的一个出栈序列,然后一步步判断它是否满足出栈序列的要求。
我们定义两个指针indexPushA
和indexPopA
分别表示入栈序列和出栈序列的索引。
1、初始化时两个指针都为0;
2、如果pushA[indexPushA] != popA[indexPopA]
, 那么应该将pushA[indexPushA]
放入栈中, indexPushA++
;
3、否则,pushA[indexPushA] == popA[indexPopA]
, 说明这个元素是放入栈中立马弹出,所以,indexPushA++
, indexPopA++
,然后应该检查popA[indexPopA]
与栈顶元素是否相等,如果相等,indexPopA++
, 并且弹出栈顶元素
4,重复2,3, 如果indexPushA > pushA.length
, 说明入栈序列访问完,此时检查栈是否为空,如果为空,说明匹配,否则不匹配。
3、解题代码
package pers.klb.jzoffer.medium;
import java.util.Stack;
/**
* @program: JzOffer2021
* @description: 栈的压入、弹出序列
* @author: Meumax
* @create: 2020-07-10 10:47
**/
public class PopOder {
public boolean IsPopOrder(int[] pushA, int[] popA) {
Stack<Integer> stack = new Stack<Integer>();
int indexPushA = 0; // 入栈序列的指针
int indexPopA = 0; // 出栈序列的指针
while (indexPushA < pushA.length) {
if (pushA[indexPushA] == popA[indexPopA]) { // 入栈马上又出栈
// 这里就省略入栈马上出栈的操作,等同于两个指针都往后移动一位
indexPushA++;
indexPopA++;
// 再判断此时的popA[indexPopA]是否刚好在栈顶
// 如果是,说明该元素就是在中间出栈的,而不是全部入栈完再出栈的
while (!stack.isEmpty() && stack.peek() == popA[indexPopA]) {
stack.pop();
indexPopA++;
}
} else { // 入栈,在后面出栈
stack.push(pushA[indexPushA]);
indexPushA++;
}
}
return stack.isEmpty();
}
}
4、解题心得
本题的技巧在于遍历入栈序列和出栈序列,当遍历到的两个元素相同,说明它是刚入栈就出栈,如果不是,则说明是在后面出栈,我们就把他入栈。在出栈了一个元素之后,继续判断pop序列的当前元素是不是在栈顶,如果是,则继续出栈。当最后栈没有元素了,说明这个pop序列就是push序列的一个可能的出栈序列。