剑指offer31 栈的压入、弹出序列 Kotlin

题目描述

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

1. 0<=pushV.length == popV.length <=1000

2. -1000<=pushV[i]<=1000

3. pushV 的所有数字均不相同

时间限制:1秒 空间限制:64M

示例1

输入:[1,2,3,4,5],[4,5,3,2,1]

返回值:true

说明:可以通过push(1)=>push(2)=>push(3)=>push(4)=>pop()=>push(5)=>pop()=>pop()=>pop()=>pop()这样的顺序得到[4,5,3,2,1]这个序列,返回true

示例2

输入:[1,2,3,4,5],[4,3,5,1,2]

返回值:false

说明:由于是[1,2,3,4,5]的压入顺序,[4,3,5,1,2]的弹出顺序,要求4,3,5必须在1,2前压入,且1,2不能弹出,但是这样压入的顺序,1又不能在2之前弹出,所以无法形成的,返回false

题目解析

题目要求判断给定的两个整数序列,其中一个序列是栈的压栈顺序,另一个序列是否可能是该栈的出栈顺序。题目给出了一些限制条件:

1.压栈序列和出栈序列的长度相等,且在1000以内。

2.序列中的元素范围在-1000到1000之间。

3.压栈序列中的所有数字都是不相同的。

解题思路

模拟压栈过程:使用一个栈结构来模拟压栈过程。

模拟出栈过程:在压栈的同时,检查当前栈顶元素是否是出栈序列中的下一个元素。

判断出栈序列:如果在任何时候,栈顶元素不是出栈序列中的下一个元素,或者在压栈完成后,出栈序列没有完全匹配,则返回false。如果整个出栈序列都被正确匹配,返回true

暴力模拟

题目中给出的数据范围在1000以内,我们可以尝试使用最直接的解法,使用一个栈来模拟整个过程。

object Solution {
    fun IsPopOrder(pushV: IntArray, popV: IntArray): Boolean {
        val stack = mutableListOf<Int>()
        var popIndex = 0 // 指向出栈序列的当前考察位置

        // 遍历压栈序列
        for (pushIndex in pushV.indices) {
            stack.add(pushV[pushIndex]) // 将当前元素压入栈中
            // 当栈不为空,且栈顶元素与出栈序列当前考察位置的元素相等时
            while (stack.isNotEmpty() && stack.last() == popV[popIndex]) {
                // 弹出栈顶元素,并考察出栈序列的下一个位置
                stack.removeAt(stack.size - 1)
                popIndex++
            }
        }
        // 如果出栈序列的所有元素都被考察完毕,则说明是一个可能的出栈序列
        return popIndex == popV.size
    }
}

在这个方法中我们使用一个栈来模拟压栈过程,同时创建一个指针或索引来跟踪出栈序列的当前位置对于压栈序列中的每个元素:将其压入栈中。再检查栈顶元素是否与出栈序列中的当前元素匹配如果匹配,将出栈序列的指针向前移动一位。如果在遍历完压栈序列后,出栈序列的指针到达了序列的末尾,则返回true;否则,返回false

在时间限制为1秒的情况下,暴力模拟方法是否可行取决于具体的输入数据。由于题目中提到压栈序列和出栈序列的长度可以到1000,暴力模拟方法可以满足题目给出的时间限制要求。

双指针

如果将压栈序列很长的情况加入考虑范围,我们可以使用双指针尝试在单次遍历中确定弹出序列是否可能。这种方法不需要使用额外的栈结构,而是通过两个指针分别在压栈序列和出栈序列上移动来解决问题。

object Solution {
    fun IsPopOrder(pushV: IntArray, popV: IntArray): Boolean {
        val stack = mutableListOf<Int>()
        var j = 0 // 出栈序列的指针

        for (i in pushV.indices) {
            stack.add(pushV[i]) // 压栈
            // 当栈不为空,且栈顶元素为出栈序列的当前元素时,出栈
            while (j < popV.size && stack.isNotEmpty() && stack.last() == popV[j]) {
                stack.removeAt(stack.size - 1) // 出栈
                j++ // 移动出栈序列的指针
            }
        }
        // 如果所有元素都正确弹出,j应该等于popV.size
        return j == popV.size
    }
}

总结

两种种解法的时间复杂度同样是O(n),其中n是压栈序列的长度。在大多数情况下,这两种方法的效率差异不大,因为它们的基本操作是相同的。双指针法的好处是不需要额外的空间来存储每个元素的索引。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值