🚩传送门:力扣题目

题目

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。
例如:序列 [LC]31. 栈的压入、弹出序列 - 图1 是某栈的压栈序列,序列 [LC]31. 栈的压入、弹出序列 - 图2是该压栈序列对应的一个弹出序列,但[LC]31. 栈的压入、弹出序列 - 图3 就不可能是该压栈序列的弹出序列。

示例 1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1] 输出:true 解释:我们可以按以下顺序执行: push(1), push(2), push(3), push(4), pop() -> 4, push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

示例 2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2] 输出:false 解释:1 不能在 2 之前弹出。

解题思路:模拟

如下图所示,给定一个压入序列 [LC]31. 栈的压入、弹出序列 - 图4 和弹出序列 [LC]31. 栈的压入、弹出序列 - 图5 ,则压入 / 弹出操作的顺序(即排列)是 唯一确定 的。
[LC]31. 栈的压入、弹出序列 - 图6
如下图所示,栈的数据操作具有 先入后出 的特性,因此某些弹出序列是无法实现的。
[LC]31. 栈的压入、弹出序列 - 图7
考虑借用一个辅助栈 [LC]31. 栈的压入、弹出序列 - 图8模拟 压入 / 弹出操作的排列。根据能否模拟成功,即可得到结果。

  • 入栈操作: 按照压栈序列的顺序执行。
  • 出栈操作: 每次入栈后,判断 栈顶元素 == 弹出序列的当前元素 是否成立,将符合弹出序列顺序的栈顶元素全部弹出。

复杂度分析

时间复杂度:[LC]31. 栈的压入、弹出序列 - 图9,其中 [LC]31. 栈的压入、弹出序列 - 图10 为列表[LC]31. 栈的压入、弹出序列 - 图11 的长度,每个元素最多入栈与出栈一次,即最多共 [LC]31. 栈的压入、弹出序列 - 图12 次出入栈操作。

空间复杂度:[LC]31. 栈的压入、弹出序列 - 图13, 辅助栈[LC]31. 栈的压入、弹出序列 - 图14最多同时存储[LC]31. 栈的压入、弹出序列 - 图15 个元素。

我的代码

  1. class Solution {
  2. public boolean validateStackSequences(int[] pushed, int[] popped) {
  3. // 全空符合
  4. if ((pushed == null || pushed.length == 0) && (popped == null || popped.length == 0)) return true;
  5. // 有一个空一个不为空,不符合
  6. if (pushed == null || pushed.length == 0 || popped == null || popped.length == 0) return false;
  7. LinkedList<Integer> stack = new LinkedList<>();
  8. int pushindex = 0;
  9. int popindex = 0;
  10. stack.push(pushed[pushindex++]);
  11. while (popindex < popped.length) {
  12. // 栈顶元素等于需要出栈的元素则出栈
  13. if (!stack.isEmpty() && stack.peek() == popped[popindex]) {
  14. stack.pop();
  15. popindex++;
  16. } else {
  17. // 合法范围内入栈
  18. if (pushindex < pushed.length)
  19. stack.push(pushed[pushindex++]);
  20. // 栈顶元素不等于出栈元素,导致一直入栈将所有元素都入栈后仍未遇到出栈元素
  21. else
  22. return false;
  23. }
  24. }
  25. // 所有出栈元素都模拟完成,返回成功状态
  26. return true;
  27. }
  28. }