发布于 

单调栈

单调栈 | 笔记整理!

单调栈 | 笔记心得

2023.5.1

42 接雨水

需要进行横向拓展 方便处理优化

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def trap(self, height: List[int]) -> int:
st=[]
ans=0
for k,v in enumerate(height):
while st and height[st[-1]]<v:
pre=st.pop()
if st:
l,r=st[-1],k
ans+=(r-l-1)*(min(height[l],height[r])-height[pre])
st.append(k)
return ans

84 柱状图中最大的矩形

同款思路 不断拓展

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
st=[-1]
heights.append(0)
ans=0
for k,v in enumerate(heights):
# 需要保证右边是最大的
while st and heights[st[-1]]>v:
pre=st.pop()
dis=k-st[-1]-1
ans=max(ans,dis*heights[pre])
st.append(k)
return ans

85 最大矩形

84基础上优化一下 注意是 只包含 1 的最大矩形,并返回其面积

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution:
def maximalRectangle(self, matrix: List[List[str]]) -> int:
# 理解了 类似于 84
n=len(matrix[0])
height=[0]*(n+1)
ans=0
for r in matrix:
for i,c in enumerate(r):
# 只包含 1 的最大矩形,并返回其面积
height[i]=0 if c=='0' else height[i]+1
ans=max(ans,self.largestRectangleArea(height))
return ans
def largestRectangleArea(self, heights: List[int]) -> int:
st=[-1]
ans=0
for k,v in enumerate(heights):
# 需要保证右边是最大的
while st and heights[st[-1]]>v:
pre=st.pop()
dis=k-st[-1]-1
ans=max(ans,dis*heights[pre])
st.append(k)
return ans

316 去除重复字母

注意唯一 和 字典序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def removeDuplicateLetters(self, s: str) -> str:
map = Counter(s)
st = []
for i in s:
# 保证唯一
if i in st:
map[i]-=1
continue
while st and st[-1]>i and map[st[-1]]:
st.pop()
map[i]-=1
st.append(i)
return ''.join(st)

321 拼接最大数

参考归并 处理所有可能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution:
def maxNumber(self, nums1: List[int], nums2: List[int], k: int) -> List[int]:
# 有所想法 立马想到归并
# 还是无从下手
def get_big_nums(nums,k):
st=[]
cnt=len(nums)-k
for i in nums:
while cnt and st and st[-1]<i:
cnt-=1
st.pop()
st.append(i)
return st[:k]

def merge_nums(a,b):
ans=[]
while a or b:
big=a if a>b else b
ans.append(big.pop(0))
return ans

return max(merge_nums(get_big_nums(nums1,i),get_big_nums(nums2,k-i)) for i in range(k+1) if i<=len(nums1) and k-i<=len(nums2))

402 移掉k位数字

移除问题 对于位数移除之后单独考虑

1
2
3
4
5
6
7
8
9
10
11
class Solution:
def removeKdigits(self, num: str, k: int) -> str:
st=[]
for i in num:
while k and st and st[-1]>i:
k-=1
st.pop()
st.append(i)
# 对于位数移除之后单独考虑
st=st[:-k] if k else st
return ''.join(st).lstrip('0') or '0'

456 132模式

本题有所参考 确实学到 处理一条之后然后完善剩余的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
def find132pattern(self, nums: List[int]) -> bool:
# 先进行一遍遍历 存左边最小的
# 从后操作即可
n=len(nums)
min_vals=[nums[0]]*n
for i in range(1,n):
min_vals[i]=min(min_vals[i-1],nums[i])

st=[]
for i in range(n-1,-1,-1):
nxt_val=-inf
while st and st[-1]<nums[i]:
nxt_val=st.pop()
if nxt_val>min_vals[i]:
return True
st.append(nums[i])
return False

496 下一个更大元素I

下一个最大/小问题

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
st=[]
map={}
for k,v in enumerate(nums2):
while st and nums2[st[-1]]<v:
idx=st.pop()
map[nums2[idx]]=v

st.append(k)
if st:map[v]=-1
print(map)
return [map[i] for i in nums1]

503 下一个更大元素 II

上一题稍微优化即可 也可以对于范围进行优化 0~2n-2即可

1
2
3
4
5
6
7
8
9
10
11
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
st=[]
n=len(nums)
ans=[-1]*n
for i in range(2*n-1): #0~2n-1 是不行的 我们需要执行到 0~2*n-2
while st and nums[st[-1]%n]<nums[i%n]:
idx=st.pop()
ans[idx%n]=nums[i%n]
st.append(i%n)
return ans

581 最短无序连续子数组

困了 直接暴力

1
2
3
4
5
6
7
8
9
10
11
class Solution:
def findUnsortedSubarray(self, nums: List[int]) -> int:
ans=sorted(nums)
if ans==nums:return 0
pre=0
n=len(nums)
while pre<n and ans[pre]==nums[pre]:pre+=1
nxt=n-1
while nxt>=0 and ans[nxt]==nums[nxt]:nxt-=1

return n-pre-(n-nxt)+1