单调栈 | 笔记心得 | 2023.5.1

51 阅读3分钟

单调栈 | 笔记心得

2023.5.1

42 接雨水

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

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 柱状图中最大的矩形

同款思路 不断拓展

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 的最大矩形,并返回其面积

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 去除重复字母

注意唯一 和 字典序

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 拼接最大数

参考归并 处理所有可能

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位数字

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

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模式

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

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

下一个最大/小问题

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即可

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 最短无序连续子数组

困了 直接暴力

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