leetcode刷题-单调栈

代码随想录单调栈|739. 每日温度、496.下一个更大元素 I、503.下一个更大元素II、42. 接雨水、84.柱状图中最大的矩形

739. 每日温度

leetcode题目链接
代码随想录文档讲解

思路

找到这个元素后面 第一个比这个元素大的元素,算它们的距离(下标之差)

暴力解法:时间复杂度n2

单调栈:时间复杂度n2

单调栈适合:求当前元素左边(右边)比当前元素大(小)的元素

单调栈中存放的是下标,存放的元素是递增(从栈顶到栈底)还是递减呢?递增(第一个比它大的元素),递减(第一个比它小的元素)

单调栈的作用: 记录遍历过的元素!!

python代码

python 复制代码
class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        answer = [0]*len(temperatures)
        stack = [0] # 存放下标
        for i in range(1, len(temperatures)):
            if temperatures[i] <= temperatures[stack[-1]]:
                stack.append(i)
            else:
                while len(stack) != 0 and temperatures[i] > temperatures[stack[-1]]:
                    answer[stack[-1]] = i - stack[-1]
                    stack.pop()
                stack.append(i)
        return answer

496.下一个更大元素 I

leetcode题目链接
代码随想录文档讲解

思路

本题本质还是对nums2采用单调栈的算法计算下一个最大元素,但是返回的result需要和nums1大小一致,顺序一致,因此对nums2中的元素计算完后需要映射回nums1,除此之外,本题的result数组应该初始化为-1

两个没有重复元素 的数组 nums1 和 nums2,采用map进行映射,使用哈希表数据结构,但是对于python实现,可以使用index函数

python代码

python index函数

nums1 = [1, 3, 5, 7]

nums1.index(5) 输出: 2

python 复制代码
class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        result = [-1]*len(nums1)
        stack = [0]
        for i in range(1, len(nums2)):
            if nums2[i] <= nums2[stack[-1]]:
                stack.append(i)
            else:
                while len(stack)!= 0 and nums2[i] > nums2[stack[-1]]:
                    if nums2[stack[-1]] in nums1: # 这里注意不要写反了,nums2[stack[-1]]和nums2[i]
                        index = nums1.index(nums2[stack[-1]])
                        result[index] = nums2[i]
                    stack.pop()
                stack.append(i)
        return result

503.下一个更大元素II

leetcode题目链接
代码随想录文档讲解

思路

本题相比前面两题,变为循环数组了(数组可以首尾相连了)

思路1: 扩容,两个数组拼在一起,然后单调栈

例如:nums = [1,2,1],扩容后:nums = [1,2,1,1,2,1]

result = [2,-1,2,2,-1,_] 取前3个即:[2,-1,2]

思路2: 用取模的方式模拟转圈的过程 (设计成环都可以这么操作)

for i in range(len(nums)*2):

i = i%len(nums)

遍历时对数组长度×2,然后实际再进行取模,所以在超出数组长度的时候,i又回来了

python代码

n = [1, 2, 3]

n*2 输出:[1, 2, 3, 1, 2, 3]

n+n 输出:[1, 2, 3, 1, 2, 3]

python 复制代码
# 思路1
class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        n = len(nums)
        nums = nums*2
        result = [-1]*len(nums)
        stack = [0]
        for i in range(1, len(nums)):
            if nums[i] <= nums[stack[-1]]:
                stack.append(i)
            else:
                while len(stack) != 0 and nums[i] > nums[stack[-1]]:
                    result[stack[-1]] = nums[i]
                    stack.pop()
                stack.append(i)
        res = result[:n]
        return res
python 复制代码
# 思路2
class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        result = [-1]*len(nums)
        stack = [0]
        for i in range(1, len(nums)*2):
            i = i%len(nums)
            if nums[i] <= nums[stack[-1]]:
                stack.append(i)
            else:
                while len(stack) != 0 and nums[i] > nums[stack[-1]]:
                    result[stack[-1]] = nums[i]
                    stack.pop()
                stack.append(i)
        return result

42. 接雨水 -- 面试常考题

leetcode题目链接
代码随想录文档讲解

思路

思路1: 暴力解法,复杂度n2

两层for循环,外层for循环一个遍历柱子,里层for循环 去找每个柱子右边比它高的第一个柱子高度及左边比它高的第一个柱子的高度是多少

思路2: 双指针优化,复杂度O(n)

提前预处理两个数组

思路3: 单调栈

这里可以借助单调栈的特性,栈内的元素是单调递增的,因此在获得了某一个元素的右边第一个比它大的元素,那么栈里的下一个元素就是左边第一个比它大的元素

栈中还是存放下标

python代码

python 复制代码
class Solution:
    def trap(self, height: List[int]) -> int:
        result= 0
        stack= [0]
        for i in range(1, len(height)):
            if height[i] <= height[stack[-1]]:
                stack.append(i)
            else:
                while stack and height[i] > height[stack[-1]]:
                    mid = stack.pop()
                    if stack:
                        w = i - stack[-1] - 1
                        h = min(height[i], height[stack[-1]]) - height[mid] # 第一次提交把这里重命名为height了,调试了半天。。
                        result += w*h
                stack.append(i)
        return result

84.柱状图中最大的矩形

leetcode题目链接
代码随想录文档讲解

思路

和接雨水题目遥相呼应,一个是求柱子外面的,一个是求柱子里面的

  1. 思路1: 暴力解法,复杂度n2

    两次for循环

    以某个柱子为中心,找左边比它矮的,右边比它矮的,确定高,然后根据距离确定宽

  2. 思路2: 双指针法

  3. 思路3: 单调栈

    此处的单调栈是单调递减的,因为要找左边和右边第一个比它小的,中间就是大于等于它的,高度就是当前柱子的高度,宽度为中间柱子的宽度;

    首位加0,(尾部加0)避免[2,4,6,8]这样单调递增的数组;(头部加0)对于[8,6,4,2]若满足当前元素大于栈顶元素,弹出后,栈为空,则不会进行计算面积,避免栈为空的情况

python代码

python 复制代码
class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        heights = [0] + heights + [0] # 或者 heights.insert(0, 0) heights.append(0)
        result = 0
        stack = [0]
        for i in range(1, len(heights)):
            if heights[i] >= heights[stack[-1]]:
                stack.append(i)
            else:
                while stack and heights[i] < heights[stack[-1]]:
                    mid = stack.pop()
                    if stack:
                        w = i - stack[-1] - 1
                        h = heights[mid]
                        result = max(result, w*h)
                stack.append(i) # 第一次忘记了这行代码
        return result
相关推荐
倔强的小石头_19 分钟前
【C语言指南】函数指针深度解析
java·c语言·算法
Yasin Chen24 分钟前
C# Dictionary源码分析
算法·unity·哈希算法
_Coin_-1 小时前
算法训练营DAY27 第八章 贪心算法 part01
算法·贪心算法
董董灿是个攻城狮6 小时前
5分钟搞懂什么是窗口注意力?
算法
Dann Hiroaki6 小时前
笔记分享: 哈尔滨工业大学CS31002编译原理——02. 语法分析
笔记·算法
qqxhb8 小时前
零基础数据结构与算法——第四章:基础算法-排序(上)
java·数据结构·算法·冒泡·插入·选择
FirstFrost --sy9 小时前
数据结构之二叉树
c语言·数据结构·c++·算法·链表·深度优先·广度优先
森焱森9 小时前
垂起固定翼无人机介绍
c语言·单片机·算法·架构·无人机
搂鱼11451410 小时前
(倍增)洛谷 P1613 跑路/P4155 国旗计划
算法
Yingye Zhu(HPXXZYY)10 小时前
Codeforces 2021 C Those Who Are With Us
数据结构·c++·算法