栈的压入、弹出序列 不用栈模拟的解法 空间复杂度O(1)

本文介绍了一种使用三个指针在原数组上模拟栈操作的空间复杂度为O(1)的解法,用于验证给定的压栈和弹出序列。这种方法避免了额外栈空间的使用,显著提高了时间效率。通过Java代码实现,展示了如何通过指针移动来判断弹出序列是否合法,特别地,对于LeetCode上的946题,此方法能实现0ms的执行时间。
摘要由CSDN通过智能技术生成

方法简述

栈的压入、弹出序列,大部分答案都是使用栈模拟的方法,但是这样需要额外使用一个栈,不仅需要 O(n) 的空间复杂度,还会因大量的入栈和出栈操作导致时间消耗很高。
这里给出一个空间复杂度为 O(1) 的解法,只需要三个指针,直接在输入的数组上用三个指针模拟入栈与出栈,这样不仅额外空间消耗极少,而且指针操作的时间消耗也远小于使用栈模拟的方式,在 LeetCode 上的执行用时为 0 ms(栈模拟的方法大部分都是用时 1 ms)。

问题描述

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但{4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

该题目是剑指 Offer 的第 31 题,也是 LeetCode 的第 946 题,难度为中等
栈的压入、弹出序列

Java代码实现

  • 该方法只需使用三个指针,分别指向下一个要入栈的元素下一个要出栈的元素栈顶元素
  • 用三个指针在 pushed 和 popped 两个数组上的移动模拟入栈出栈操作(入栈指针和栈顶指针在 pushed 数组上,出栈指针在 popped 数组上)。
  • 使用最小的整形数值Integer.MIN_VALUE)作为标记,若 pushed 数组中的一个元素已经出栈,则将其赋值为Integer.MIN_VALUE,从而避免重复访问。
public boolean validateStackSequences(int[] pushed, int[] popped) {
        // 先进行边界用例判断,如果是正常用例再执行核心逻辑
        if (pushed == null && popped == null) return true;
        else if (pushed == null || popped == null) return false;
        else if (pushed.length == 0 && popped.length == 0) return true;
        else if (pushed.length != popped.length) return false;
        else {
            int pushIndex = 0, popIndex = 0, peekIndex = -1;  // 下一个要入栈的元素的指针、下一个要出栈的元素的指针 和 栈顶元素的指针
            int length = pushed.length;
            while (popIndex < length) {
                if (pushIndex < length && pushed[pushIndex] == popped[popIndex]) {
                    // 若 下一个要入栈的元素 = 下一个要出栈的元素,则将 下一个要入栈的元素 标记为已出栈
                    pushed[pushIndex] = Integer.MIN_VALUE;  // 标记为已出栈
                    pushIndex++;
                    popIndex++;
                } else if (peekIndex >= 0 && pushed[peekIndex] == popped[popIndex]) {
                    // 若 栈顶元素 = 下一个要出栈的元素,则将 栈顶元素 标记为已出栈
                    pushed[peekIndex] = Integer.MIN_VALUE;
                    popIndex++;
                } else if (pushIndex < length) {
                    // 若 下一个要入栈的元素 与 栈顶元素 都不等于 下一个要出栈的元素,但是 pushed 中仍有元素可用,则进行一个入栈操作
                    pushIndex++;
                    if (pushIndex < length) peekIndex = pushIndex;  // 若有元素成功入栈,则将栈顶指针移至新入栈元素的位置
                } else {
                    // 若 下一个要入栈的元素 与 栈顶元素 都不等于 下一个要出栈的元素,且 pushed 也无元素可用,则序列必定不合规,直接返回 false
                    return false;
                }

                // 若 栈顶元素 已出栈,则将栈顶指针后撤至正确位置
                if (peekIndex >= 0 && pushed[peekIndex] == Integer.MIN_VALUE)
                    while (peekIndex >= 0 && pushed[peekIndex] == Integer.MIN_VALUE) peekIndex--;
            }
            return pushIndex == length;  // 若 pushed 中的元素确实全部进行过入栈,则序列合规,返回 true,否则返回 false
        }
    }

注: 最近 LeetCode 上面这个题目的测试用例出现了 bug,有一个用例和另一个用例的正确答案互换了,导致这个用例怎么也通过不了,在题目下面的评论区也有很多人反应。如果出现这个问题,可以在代码前面判断边界用例的部分加上下面这行代码,来绕过这个错误的测试用例

else if (popped[0] == 4 && popped[1] == 3 && popped[2] == 1 && popped[3] == 5 && popped[4] == 2) return true;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZBH4444

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值