日常系列LeetCode《10·栈和队列篇》
Posted 常某某的好奇心
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了日常系列LeetCode《10·栈和队列篇》相关的知识,希望对你有一定的参考价值。
数据规模->时间复杂度
<=10^4 😮(n^2)
<=10^7:o(nlogn)
<=10^8:o(n)
10^8<=:o(logn),o(1)
总结(栈和队列)-操作受限的线性结构
'''
#基本操作
'''
def test(self) -> None:
stack = list()
# 压栈
stack.append(2)
stack.append(3)
# 栈顶元素
top = stack[-1]
# 栈是否为空
is_empty = not stack
# 出栈
stack.pop()
lc 20【top100】:有效的括号
https://leetcode.cn/problems/valid-parentheses/
提示:
1 <= s.length <= 104
s 仅由括号 ‘()[]’ 组成
#方案一:
class Solution:
def isValid(self, s: str) -> bool:
if len(s)%2 != 0:return False
#o(n),o(n)
stack=[]
for c in s:
if c=='('or c=='' or c=='[':
stack.append(c)
else:
if not stack:return False
#
tp=stack.pop()
if c==')' and tp !='(':return False
if c=='' and tp !='':return False
if c==']' and tp !='[':return False
return not stack
#方案二:map扩展优化
class Solution:
def isValid(self, s: str) -> bool:
if len(s)%2 != 0:return False
#o(n),o(n)
stack=[]
mp="(": ")","[": "]","": ""
for c in s:
if c in mp:
stack.append(c)
else:
if not stack:return False
#
tp=stack.pop()
if c !=mp.get(tp):return False
return not stack
lc 71【剑指 017】 :简化路径
https://leetcode.cn/problems/simplify-path/
提示:
1 <= path.length <= 3000
path 由英文字母,数字,‘.’,‘/’ 或 ’ ’ 组成。
path 是一个有效的 Unix 风格绝对路径。
class Solution:
def simplifyPath(self, path: str) -> str:
s=[c for c in path.split("/") if c != "" and c !="."]#注意""
#
stack=[]
for c in s:
if c ==".." and not stack:continue
elif c==".." and stack:stack.pop()
else:stack.append(c)
#
return "/"+'/'.join(stack)#key:做双向队列处理
lc 394【top100】:字符串解码
https://leetcode.cn/problems/decode-string/
提示:
1 <= s.length <= 30
s 由小写英文字母、数字和方括号 ‘[]’ 组成
s 保证是一个 有效 的输入。
s 中所有整数的取值范围为 [1, 300]
class Solution:
def decodeString(self, s: str) -> str:
#o(n)
res=''
numstack=[]
strstack=[]
#o(n)
num=0
for c in s:
if c>='0' and c<='9':
num=num*10+ord(c)-ord('0')
elif c=='[':#压栈标志
numstack.append(num)
strstack.append(res)
num,res=0,''
elif c==']':#出栈标志
items=res#出发点
for i in range(1,numstack.pop()):
res+=items
res=strstack.pop()+res
else:res+=c
return res
lc 224:基本计算器
https://leetcode.cn/problems/basic-calculator/
提示:
1 <= s.length <= 3 * 105
s 由数字、‘+’、‘-’、‘(’、‘)’、和 ’ ’ 组成
s 表示一个有效的表达式
‘+’ 不能用作一元运算(例如, “+1” 和 “+(2 + 3)” 无效)
‘-’ 可以用作一元运算(即 “-1” 和 “-(2 + 3)” 是有效的)
输入中不存在两个连续的操作符
每个数字和运行的计算将适合于一个有符号的 32位 整数
class Solution:
def calculate(self, s: str) -> int:
#o(n)
presign=1
num=0
res=0
#o(n)
stack=[]
for c in s:
if c>='0' and c<='9':
num=num*10+ord(c)-ord('0')
elif c=="+":#更新,初始
res += presign*num
presign,num=1,0
elif c=='-':#更新,初始
res += presign*num
presign,num=-1,0
elif c=='(':#入栈,顺序,初始
stack.append(res)
stack.append(presign)
res,presign=0,1
elif c==')':#出栈,顺序,初始
res+=presign*num
res*=stack.pop()
res+=stack.pop()
num=0
return res+presign*num
lc 227:基本计算器二
https://leetcode.cn/problems/basic-calculator-ii/
提示:
1 <= s.length <= 3 * 105
s 由整数和算符 (‘+’, ‘-’, ‘*’, ‘/’) 组成,中间由一些空格隔开
s 表示一个 有效表达式
表达式中的所有整数都是非负整数,且在范围 [0, 231 - 1] 内
题目数据保证答案是一个 32-bit 整数
#先乘除,后累加
class Solution:
def calculate(self, s: str) -> int:
#o(n)
stack = []
#
presign='+'
num=0
for i in range(len(s)):
if s[i].isdigit():
num=num*10 + ord(s[i])-ord('0')
if i==len(s)-1 or not s[i].isdigit() and s[i]!=' ' :#例如"3+2*2":最后一个元素依然需要处理(而不是在最后简单的加减)
#if i==len(s)-1 or s[i] in '+-*/':
if presign=="+":stack.append(num)
elif presign=='-':stack.append(-num)
elif presign=='*':stack.append(num*stack.pop())
else:stack.append(int(stack.pop()/num))
#
num=0#初始
presign=s[i]#更新
#
return sum(stack)
lc 946【剑指 31】:验证栈序列
https://leetcode.cn/problems/validate-stack-sequences/
提示:
1 <= pushed.length <= 1000
0 <= pushed[i] <= 1000
pushed 的所有元素 互不相同
popped.length == pushed.length
popped 是 pushed 的一个排列
class Solution:
def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
stack=[]
i=0
for num in pushed:
stack.append(num)
while stack and stack[-1]==popped[i]: #key:while,否则无法一直比较,i不再更新
stack.pop()
i+=1
return i==len(popped)
单调栈
'''
#找出数组中右边第一个比我小的元素
'''
def findRightSmall(self, nums: List[int]) -> List[int]:
#o(n)
res=[-1]*len(nums)
#o(2n):单增栈
stack=list()
for i in range(len(nums)):
while stack and nums[i]<nums[stack[-1]]:#右第一小
res[stack[-1]]=i
stack.pop()
stack.append(i) #元素
return res
'''
#找出数组中右边第一个比我大的元素
'''
def findRightLarger(self, nums: List[int]) -> List[int]:
#o(n)
res=[-1]*len(nums)
stack=list()
#o(2n):单减栈
for i in range(len(nums)):
while stack and nums[i]>nums[stack[-1]]:#右第一大
res[stack[-1]]=i
stack.pop()
stack.append(i)
return res
'''
#找出数组中左边离我最近比我小的元素
'''
def findLeftSmall(self, nums: List[int]) -> List[int]:
res=[-1]*len(nums)
stack=[]
#单增栈(右->左)
for i in range(len(nums)-1,-1,-1):
while stack and nums[i]<nums[stack[-1]]:#左第一小
res[stack[-1]]=i
stack.pop()
stack.append(i)
return res
'''
#找出数组中左边离我最近比我大的元素
'''
def findLeftLager(self, nums: List[int]) -> List[int]:
res=[-1]*len(nums)
stack=[]
#单减栈(右->左)
for i in range(len(nums)-1,-1,-1):
while stack and nums[i]>nums[stack[-1]]:#左第一大
res[stack[-1]]=i
stack.pop()
stack.append(i)
return res
lc 739【剑指 038】【top100】:每日温度
https://leetcode.cn/problems/daily-temperatures/
提示:
1 <= temperatures.length <= 10^5
30 <= temperatures[i] <= 100
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
n=len(temperatures)
if n==1:return 0
#单减栈
stack=[]
res=[0]*n
for i in range(n):
while stack and temperatures[i]>temperatures[stack[-1]]:#右第一大
res[stack[-1]]=i-stack[-1]
stack.pop()
stack.append(i)
return res
lc 42【top100】:接雨水
https://leetcode.cn/problems/trapping-rain-water/
提示:
n == height.length
1 <= n <= 2 * 10^4
0 <= height[i] <= 10^5
#暴力
class Solution:
def trap(self, height: List[int]) -> int:
n = len(height)
if n <= 2: return 0
#o(n):预计算最大值
leftmax=[0]*n
leftmax[0]=height[0]
rightmax=[0]*n
rightmax[n-1]=height[n-1]
for i in range(1,n):
leftmax[i]=max(leftmax[i-1],height[i])
for i in range(n-2,-1,-1):
rightmax[i]=max(rightmax[i+1],height[i])
#o(n)
res=0
for i in range(1,n-1):
max_height=min(leftmax[i],rightmax[i])
if max_height>height[i]:
res+=max_height-height[i]
return res
#双指针(最优)
class Solution:
def trap(self, height: List[int]) -> int:
n = len(height)
if n <= 2: return 0
#o(1):变量代替数组
left,right=0,n-1
leftmax=rightmax=0
#o(n):
res=0
while left<right:
leftmax=max(leftmax,height[left])
rightmax=max(rightmax,height[right])
if height[left]<height[right]:#key:低洼处存水
res+=leftmax-height[left]
left+=1
else:
res+=rightmax-height[right]
right-=1
return res
#单调栈
class Solution:
def trap(self, height: List[int]) -> int:
n = len(height)
if n <= 2: return 0
#o(n):
stack=[]
res=0
for i in range(n):
while stack and height[i]>height[stack[-1]]:
low=stack.pop()
if not stack:break
left=stack[-1]
#
weight=i-left-1
heigt=min(height[i],height[left])-height[low]
res+=weight*heigt
stack.append(i)
#
return res
lc 84【剑指 039】:柱状图中最大的矩
https://leetcode.cn/problems/largest-rectangle-in-histogram/
提示:
1 <= heights.length <=10^5
0 <= heights[i] <= 10^4
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
#单调栈一次遍历(融合为第二种方案)实现枚举高
n=len(heights)
#o(n),o(n)
left=[-1]*n
right=[n]*n
stack=[]
for i in range(n):
while stack and heights[stack以上是关于日常系列LeetCode《10·栈和队列篇》的主要内容,如果未能解决你的问题,请参考以下文章