20. Valid Parentheses
- 思路是左侧的符号压栈;每次遇到不是左侧的符号pop栈顶元素看一下匹不匹配(hashtable);
- 注意几种特殊情况
[
: stack最后还有残余;]
:起始元素是右侧元素;{(})
:乱搭;
class Solution:
def isValid(self, s: str) :
dic = {'(':')', '{':'}', '[':']'}
stack = []
for char in s:
if char in dic:
stack.append(char)
else:
if stack:
tmp = stack.pop()
if dic[tmp] != char:
return False # 3.
else:
return False # 2.
return not stack # 1.
155. Min Stack
- 一个栈stack正常,一个栈helper维护一个最小栈orz,在insert和pop时候需要对helper动态修改;
- 时空复杂度蛮高…
class MinStack:
def __init__(self):
self.stack = []
self.helper = []
def push(self, val: int):
self.stack.append(val)
# 动态修改helper
if self.helper and self.helper[-1] < val:
for index in range(len(self.helper)):
if self.helper[index] < val:
self.helper.insert(index, val)
break
else:
self.helper.append(val)
def pop(self):
tmp = self.stack.pop()
# 动态修改helper
for index in range(len(self.helper)):
if self.helper[index] == tmp:
del self.helper[index]
break
def top(self):
return self.stack[-1]
def getMin(self):
return self.helper[-1]
150. Evaluate Reverse Polish Notation
- 很显然的一个stack的应用
- 不是op的压栈;
- 遇到op的pop出两个元素,op之后压栈;
- 输出;
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack = []
op = ['+', '-', '*', '/']
tmp = 0
for token in tokens:
if token not in op:
stack.append(token)
else:
right = int(stack.pop())
left = int(stack.pop())
if token == '+':
tmp = left + right
if token == '-':
tmp = left - right
if token == '*':
tmp = left * right
if token == '/':
tmp = left / right
stack.append(tmp)
return int(stack[-1])
22. Generate Parentheses
739. Daily Temperatures
- 维护一个单调栈,栈内存放的元素从底部是降序的【ps:存的Index,后面要用计算距离】
- 若新的元素<栈顶元素:压栈;
- 若新的元素>栈顶元素:pop栈顶元素[while直到到第一种情况]
- 所以while的条件就综合成为while stack and t[stack[-1]] < t[index];
class Solution:
def dailyTemperatures(self, t):
stack = []
res = [0] * len(t)
for index in range(len(t)):
while stack and t[stack[-1]] < t[index]:
index2 = stack.pop()
res[index2] = index - index2
stack.append(index)
return res
853. Car Fleet
- 哈哈哈哈每次做不出来看到nc的图解都要大呼精彩!
- 每辆车如果可以在目的地前(包括目的地)追上,由于是单行道,集体降速哈哈哈哈;
- nc的思路是转化成到达target的时间t,维护一个stack存放按position大小降序排列的🚗到达target的时间;
- 对每个t压栈,都和压栈前的栈顶t做比较,如果当前压栈的t更小,那么说明是一个车队了,我们选择保留原车头就可以了,所以把当前压栈的 t pop掉;
嘶就是按position降序后,每辆车计算一下到target的时间t,[t1,t2,…,tn];问题转化成739的问题,比739还简单一点,只需要维护一个单调栈,栈顶元素为当前最大值(递增的栈);
好吧 批了皮(sorted+计算t)我就不认得它了…
nc的原版是ver1,但是我不喜欢先压栈2333,ver2比较对我的习惯2333
class Solution:
def carFleet(self, target, position, speed):
pair = [[p, s] for p, s in zip(position, speed)]
stack = []
for p, s in sorted(pair)[::-1]:
stack.append((target - p) / s)
if len(stack) >= 2 and stack[-1] <= stack[-2]:
stack.pop()
return len(stack)
def carFleet2(self, target, position, speed):
pair = sorted([[p, s] for p, s in zip(position, speed)])[::-1]
stack = [(target - pair[0][0]) / pair[0][1]]
for p, s in pair[1:]:
cur = (target - p) / s
if cur > stack[-1]:
stack.append(cur)
return len(stack)
84. Largest Rectangle in Histogram
nc yyds!!!
问题拆解!问题拆解!!问题拆解!!!
- 思路:维护一个单调栈;
- 从图1开始:三个特殊情况;当前长后短时,长的无法extend,以它为height的高度的只有他自己[形象点就是拿一把刀切从它height切过去,只有它自己会受伤嗯],所以它既然不能extend伤害别人,就把他pop出来【好家伙,寻思着是一个恶人栈吗】;当前短后长时或者前后等长时,我们就把他们留在栈内,他们这个height切过去很有杀伤力哈哈哈哈;
- 这里会有一个trick:
- stack里存的是pair:index, height,不是会出现前长后短然后把这个长的pop掉,那么我们的问题是,要append的这个短的Index应该是什么呢?
- !是的!我们要注意到!我们pop掉的都是比现在我们要Insert的height都要大的!最后一个pop掉的index是我们可以向前extend当前height的最大长度[为后面计算留在单调栈里的Area做铺垫啦]![因为我们前面维护的就是一个单调非降栈哈哈,所以你停下来的时候,你当前的栈顶元素已经比你小了,所以你没法继续向前extend啦]!
谁人不说一句妙呢???我菜我先说了哈哈哈哈!
- 总的来说是求最大的矩形面积nc的想法是分成两步来完成:
- 构造单调栈:当前压栈为栈内的最大height;顺便计算被pop出来的元素的最大矩形面积;压栈记得index的trick;
- 单调栈内height的最大矩形面积更新maxArea;
class Solution:
def largestRectangleArea(self, heights):
stack = []
maxArea = 0
for index, height in enumerate(heights):
start = index
while stack and height < stack[-1][1]:
index2, height2 = stack.pop()
maxArea = max(maxArea, height2 * (index - index2))
start = index2
stack.append([start, height])
for index, height in stack:
maxArea = max(maxArea, height * (len(heights) - index))
return maxArea
- 然后去看了一眼美版lc的高vote的回答!
Largest Rectangle In Histogram
I am glad I finally did.
泪目了啊!向blog主学习!
的确发现nc的花费的额外的空间开销更容易理解一些2333,是我愚钝了!