一、栈的进阶:
1、最小栈:
《LeetCode 155. 最小栈》
题目:
示例:
输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
代码框架:
class MinStack:
def __init__(self):
def push(self, val: int) -> None:
def pop(self) -> None:
def top(self) -> int:
def getMin(self) -> int:
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
思路:
- push()方法: 每当push()新值进来时,如果 小于等于 min_stack栈顶值,则一起push()到min_stack,即更新了栈顶最小值;
- pop()方法: 判断将pop()出去的元素值是否是min_stack栈顶元素值(即最小值),如果是则将min_stack栈顶元素一起pop(),这样可以保证min_stack栈顶元素始终是stack中的最小值。
- getMin()方法: 返回min_stack栈顶即可。
- min_stack作用分析:
min_stack等价于遍历stack所有元素,把升序的数字都删除掉,留下一个从栈底到栈顶降序的栈。
相当于给stack中的降序元素做了标记,每当pop()这些降序元素,min_stack会将相应的栈顶元素pop()出去,保证其栈顶元素始终是stack中的最小元素。
实现代码:
class MinStack:
def __init__(self):
self.stack = []
self.min_stack = [math.inf]
def push(self, x: int) -> None:
self.stack.append(x)
self.min_stack.append(min(x, self.min_stack[-1]))
def pop(self) -> None:
self.stack.pop()
self.min_stack.pop()
def top(self) -> int:
return self.stack[-1]
def getMin(self) -> int:
return self.min_stack[-1]
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
2、用栈实现队列:
《LeetCode 232. 用栈实现队列》
题目:
示例:
输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false
代码框架:
class MyQueue:
def __init__(self):
def push(self, x: int) -> None:
def pop(self) -> int:
def peek(self) -> int:
def empty(self) -> bool:
# 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()
思路:
实现代码:
class MyQueue(object):
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, x):
self.stack1.append(x)
def pop(self):
if not self.stack2:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
def peek(self):
if not self.stack2:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2[-1]
def empty(self):
return not self.stack1 and not self.stack2
# 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()
3、直方图最大矩形:
《LeetCode 84. 柱状图中最大的矩形》
题目:
示例:
代码框架:
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
思路:
首先,要想找到第 i 位置最大面积是什么?
是以i 为中心,向左找第一个小于 heights[i]
的位置 left_i
;向右找第一个小于于 heights[i]
的位置 right_i
,即最大面积为 heights[i] * (right_i - left_i -1)
,如下图所示:
所以,我们的问题就变成如何找 right_i
和 left_i
?
最简单的思路就是,就是暴力法,直接分别在 i
左右移动。
实现代码:
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
stack = []
heights = [0] + heights + [0]
res = 0
for i in range(len(heights)):
#print(stack)
while stack and heights[stack[-1]] > heights[i]:
tmp = stack.pop()
res = max(res, (i - stack[-1] - 1) * heights[tmp])
stack.append(i)
return res
二、队列进阶:
1、辅助队列:
《LeetCode 225. 用队列实现栈》
题目:
示例:
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
代码框架:
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
思路:
实现代码:
from collections import deque
class MyStack:
def __init__(self):
"""
Initialize your data structure here.
"""
self.data = deque()
self.help = deque()
def push(self, x: int) -> None:
"""
Push element x onto stack.
"""
self.data.append(x)
def pop(self) -> int:
"""
Removes the element on top of the stack and returns that element.
"""
while len(self.data) > 1:
self.help.append(self.data.popleft())
tmp = self.data.popleft()
self.help,self.data = self.data,self.help
return tmp
def top(self) -> int:
"""
Get the top element.
"""
while len(self.data) != 1:
self.help.append(self.data.popleft())
tmp = self.data.popleft()
self.help.append(tmp)
self.help,self.data = self.data,self.help
return tmp
def empty(self) -> bool:
"""
Returns whether the stack is empty.
"""
return not bool(self.data)
2、单调队列:
《LeetCode 1696. 跳跃游戏 VI》
题目:
示例:
代码框架:
class Solution:
def maxResult(self, nums: List[int], k: int) -> int:
思路:
实现代码:
class Solution:
def maxResult(self, nums: List[int], k: int) -> int:
q = collections.deque()
for i,num in enumerate(nums):
while q and q[0][1]+k<i:
q.popleft()
cur = q[0][0]+num if q else num
while q and cur>q[-1][0]:
q.pop()
q.append((cur,i))
return q[-1][0]