队和栈
栈的压入与弹出序列 剑指 offer 31
eg:pushed = [1,2,3,4,5],poped = [4,5,3,2,1] True
pushed = [1,2,3,4,5],poped=[4,3,5,1,2] False
class Soultion:
#给什么条件就纯模拟该过程即可
def validateStackSequences(self,pushed,popped):
stack = []
start = 0
for i in pushed:
stack.append(i)
while stack and stack[-1]==popped[start]:
#关键在这里
stack.pop()
start+=1
if not stack:
return True
else:
return False
- 先想清楚流程,伪代码是先找一个stack往里压入值,直到栈顶的那个值是poped的首值开始往出弹,poped要往后挪移位。
- 关键是stack这个地方,是一个栈,能否形成栈的关键是能否把他们都清空。
- 这是另一种模式,不同于字符串的移动,这个是一个往里压,一直压,所以外面有for,满足条件才做一个操作。理解题意才是最难的
最小值栈 lc 155
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self.stack = []
self.helpstack = []
def push(self, x: int) -> None:
self.stack.append(x)
if len(self.helpstack)==0 or x<self.helpstack[-1]:
self.helpstack.append(x)
else:
self.helpstack.append(self.helpstack[-1])
def pop(self) -> None:
if len(self.stack) != 0:
self.stack.pop()
self.helpstack.pop()
def top(self) -> int:
if len(self.stack) != 0:
return self.stack[-1]
def getMin(self) -> int:
if len(self.helpstack)!=0:
return self.helpstack[-1]
- 和上一个题目一样是模拟过程,该过程每次都保存栈顶的最大值,出栈时候能一直保持。
- 这个模式很好,计算当前为止最大和最小的值,用另外一个数组来保存内容
有效的括号 lc 20
class Solution:
def isValid(self, s: str) -> bool:
stack = []
adict = {'(':')','[':']','{':'}'}
for i in s:
if i in adict:
stack.append(i)
else:
if len(stack)==0:
return False
#核心
elif i!=adict[stack.pop()]:
return False
else:
pass
#栈出完了还有剩余是错误的
if len(stack)!=0:
return False
else:
return True
- 一个经典的题目,栈只负责保存括号的内容
224,227 加减乘除括号计算器
class Solution:
def caculate2(self,s):
def hepler(s):
# 这个sign维护的是之前的符号
sign = '+'
stack = []
num = 0
while len(s)>0:
c = s.pop(0)
if c.isdigit():
num = num*10+int(c)
if c == '(':
num = hepler(s)
if (not c.isdigit() and c !=' ') or len(s)==0:
if sign=='+':
stack.append(num)
elif sign=='-':
stack.append(-num)
elif sign=='*':
stack[-1] = stack[-1]*num
elif sign=='/':
stack[-1] = int(stack[-1] / float(num))
num=0
sign=c
if c == ")":break
return sum(stack)
return hepler(list(s))
- 依次入栈,如果±则全部入了之后求和,如果*和/当时就算末尾。
- 如果是括号则是递归。先算了括号再把他入栈。
- 用pop和while非常的方便,否则如果是序号挺麻烦的。
单调栈问题
要k个数,不要k个数,变成最大或者最小。
402. 移掉 K 位数字
class Solution:
def removeKdigits(self, num: str, k: int) -> str:
stack = []
need_num = len(num)-k
for i in num:
while k and stack and stack[-1]>i:
stack.pop()
k-=1
stack.append(i)
res = ''.join(stack[:need_num]).lstrip('0')
if res=='':
return '0'
else:
return res
- 问题的特点是移除几个位置,既然是数字,位置非常重要,在前面的都是小的即整个数字呈现上升趋势是要比相同位数呈现下降趋势的数字小。所以最小用单调增栈。最大用相反的。
- ‘0’的另一种解决方案,第一种是第一位*10往后加,这里使用的是lstrip (0)。
- 最后保留的位数防止全部是上升的,那肯定是相同位数留前面比后面的小。
lc 316. 去除重复字母
class Solution:
def removeDuplicateLetters(self, s: str) -> str:
adict = {}
for i,v in enumerate(s):
adict[v]=i
stack=[]
for i,v in enumerate(s):
if v in stack:
continue
while stack and stack[-1]>s[i]:
if adict[stack[-1]]>i:
stack.pop()
stack.append(v)
return ''.join(stack)
- 流程比上一题多了,不重复,且字典序最小。
- 因为是单调上升的所以用模板,想要去除他需要保证他在后面还有。否则不能去除。
- 因为是单调上升的,所以如果再出现同样的,因为不能重复,继续。
321. 拼接最大数
class Solution:
def maxNumber(self, nums1: List[int], nums2: List[int], k: int) -> List[int]:
def get_max_k_val(nums,num):
stack = []
del_num = len(nums)-num
for i in nums:
while del_num and stack and stack[-1]<i:
stack.pop()
del_num-=1
stack.append(i)
return stack[:num]
def merge(A, B):
# 得到答案后这样拼接绝对是最大的,不能有其他拼接方式比这个大
ans = []
while A or B:
bigger = A if A > B else B
ans.append(bigger.pop(0))
return ans
res = []
for i in range(k+1):
# i在这个范围内但是要受限于长度,之前写法没有限制长度
if i <= len(nums1) and k - i <= len(nums2):
res = max(res,merge(get_max_k_val(nums1, i), get_max_k_val(nums2, k - i)))
return res
# j没有必要再循环了,因为已经找到了就是k-i,只要限制范围就行了
# res=[]
# for i in range(k+1):
# for j in range(i+1,k-i+1):
# if i <= len(nums1) and j<=len(nums2):
# stack1 = get_max_k_val(nums1,i)
# stack2 = get_max_k_val(nums2,j)
# res = max(res,merge(stack1,stack2))
# return res
- 本质还是选k个,只不过是各自选几个数,注意选出来之后只有唯一一种拼接方式会让该数最大
- list的拼接可以直接上面那么写,因为比的是第一个位置的值。
- 选出来i之后没必要再次的循环。一次就选出两个数字,然后选大小吧。
数组中元素与下一个比它大的元素之间的距离 lc 739
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
class Solution:
def dailyTemperatures(self, T):
# 用于存放序号
stack = []
res = [0] * len(T)
for i in range(len(T)):
# 每次都是当前和未弹出的作比较,维护了一个单调递减的栈
# 如果有递增的值则开始弹栈,给res去补这个值
while stack and T[stack[-1]] < T[i]:
diff = i - stack[-1]
tmp_index = stack.pop()
res[tmp_index] = diff
stack.append(i)
return res
- 单调栈存放序号,只能有这么一个功能,遇到比他大的求一下差值,放在另一个数据结构中。
循环数组中比当前元素大的下一个元素 lc 503
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
输入: [1,2,1]
输出: [2,-1,2]
class Solution:
def nextGreaterElements(self, nums):
stack = []
res = [-1]*len(nums)
for i in range(2*len(nums)):
i = i%len(nums)
while stack and nums[stack[-1]]<nums[i]:
tmp_index = stack.pop()
res[tmp_index] = nums[i]
stack.append(i)
return res
- 循环数组的解决方案,i的遍历范围是2*len,每次取式i%len,i取余正常的长度就可以把多出来一倍的内容回归。遍历到头就走了一周。
用栈实现队列 lc 232
class MyQueue:
def __init__(self):
"""
Initialize your data structure here.
"""
self.stack = []
def push(self, x: int) -> None:
"""
Push element x to the back of queue.
"""
self.stack.append(x)
def pop(self) -> int:
"""
Removes the element from in front of queue and returns that element.
"""
return self.stack.pop(0)
def peek(self) -> int:
"""
Get the front element.
"""
return self.stack[0]
def empty(self) -> bool:
"""
Returns whether the queue is empty.
"""
if len(self.stack)==0:
return True
else:
return False
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()
用队列实现栈 lc 225
class MyStack:
def __init__(self):
"""
Initialize your data structure here.
"""
self.queue=[]
def push(self, x: int) -> None:
"""
Push element x onto stack.
"""
self.queue.append(x)
def pop(self) -> int:
"""
Removes the element on top of the stack and returns that element.
"""
return self.queue.pop()
def top(self) -> int:
"""
Get the top element.
"""
return self.queue[-1]
def empty(self) -> bool:
"""
Returns whether the stack is empty.
"""
if len(self.queue)==0:
return True
else:
return False
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()