栈的压入、弹出序列
方法一–借助辅助空间
思路
借助一个辅助栈,把压入序列按顺序存储到辅助栈中,当辅助栈不为空且栈顶元素等于弹出序列第一个元素时,弹出辅助栈的栈顶元素,在判断输出序列的下一个元素
#方法一
# -*- coding:utf-8 -*-
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
assist_stack = []
j = 0
for i in pushV:
assist_stack.append(i)
while assist_stack and assist_stack[-1] == popV[j]:
assist_stack.pop()
j+=1
return len(assist_stack) == 0
方法一参考的以下博客:
https://blog.csdn.net/weixin_40941966/article/details/80798880
方法二–不借助辅助空间
思路:
如果popV是压入栈序列pushV的弹出序列应满足下列的规律:
该规律用白话叙述不容易理解,通过下面的例子进行解释
pushV = [1,2,3,4,5]
popV1 = [4,5,3,2,1]
popV2 = [4,3,5,1,2]
popV1是pushV的弹出序列,popV2不可能是pushV的弹出序列。
首先,我们看弹出序列的的首元素,popV1和popV2都为4,然后再压入栈序列中进行搜索,pushV[3] = 4
然后,对上面的序列进行pop操作,pop出元素4,可以得到
pushV = [1,2,3,5]
popV1 = [5,3,2,1]
popV2 = [3,5,1,2]
最关键的地方就在下面,弹出序列的下一个元素(popV1中的5,popV2中的3)应该处于pushV的什么位置????
经过分析,弹出序列的下一个元素必须处于上一步pop出的元素(即4)左边的一个元素或者右边所有元素中
此题的关键在于这一句话,不明白的细细品
代码有两个版本,思路一样,版本二相比于版本一节省时间,
建议先看版本一再看版本二,版本一更容易理解
# 版本二
#相比于版本一节省时间
# -*- coding:utf-8 -*-
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
temp = 1
error_flag = True
while popV:
#不再从头开始遍历,而是直接看正确位置范围内有没有该元素
for i in range(temp-1,len(pushV)):
if popV[0] == pushV[i]:
temp = i
popV.pop(0)
pushV.pop(i)
#如果在正确范围内有该元素,则error_flag = False
error_flag = False
break
#上面的for循环执行完之后,如果没有在正确范围内找到(即error_flag没修改),
# 则说明该序列不是pushV的弹出序列
if error_flag:
return False
#重置错误标志
error_flag = True
return True
"""
下面的代码实现上面的描述,但是下面的for循环每次都遍历整个序列,时间比较长,在牛客网上无法通过。
最上面的代码是对下面代码的修改,节省了时间,可以在牛客网通过。
# 版本一
# -*- coding:utf-8 -*-
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
#为什么初始化为1,以为下面有temp-1
temp = 1
while popV:
for i in range(len(pushV)):
#寻找本次弹出序列元素在popV的位置
if popV[0] == pushV[i]:
#判断位置是否正确
if i < temp-1:
return False
#temp用于记录i的位置,方便判断弹出序列的下一元素是否处于正确位置
temp = i
popV.pop(0)
pushV.pop(i)
#终止for循环
break
#弹出序列所有元素位置都正确,则 return True
return True
"""