单调栈II: leetcode 581、901、42、84

Leetcode 单调栈问题总结(超详细!!!) 0x00 单调栈主要回答这样的几种问题 比当前元素更大的下一个元素 比当前元素更大的前一个元素 比当前元素更小的下一个元素 比当前元素更小的前一个元素 0x01 问题一 维护一个单调递减的栈。 Leetcode 496:下一个更大元素 I(超详细的解法!!!) Leetcode 503:下一个更大元素 II(超详细的解法!!!) Leetcode 739:每日温度(超详细的解法!!!) cl... 阅读详情

leetcode 581:最短无序连续子数组

题目描述:
给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

请你找出符合题意的 最短 子数组,并输出它的长度。

示例 1:
输入:nums = [2,6,4,8,10,9,15]
输出:5
解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

示例 2:
输入:nums = [1,2,3,4]
输出:0

示例 3:
输入:nums = [1]
输出:0

提示:
1 <= nums.length <= 104
-105 <= nums[i] <= 105

思路1: 排序
本题是要找到不满足升序部分的数组的长度,所以可以对数列进行排序,排序后对比就可以知道所求的长度。

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        nums_s = sorted(nums)
        res = []
        for i in range(len(nums)):
            if nums_s[i] != nums[i]:
                res.append(i) 
        return max(res) - min(res) + 1 if res else 0

思路2:
因为求得是不满足单调性的长度,所以想到用单调栈求出不满足单调的位置,就可以求出来长度。
这里需要注意的是,我们可以观察到数组是这样分布的【单调上升,所求部分,单调上升】所以我们需要求两部分的临界点,采用了两次单调栈的想法,一个单调递增栈求左边边界,单调递减栈求右边边界。分别是从左右两边开始遍历的;这里需要注意的是,只用一次单调栈是无法求出两个边界的,因为栈的增减是确定的,只能求出一个;

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        key_1, key_2 = len(nums), 0
        stack = []
        for i in range(len(nums)):
            while stack and nums[i] < nums[stack[-1]]:
                peek = stack.pop()
                key_1 = min(key_1, peek)
            stack.append(i)

        stack = []
        for j in range(len(nums)-1, -1, -1):
            while stack and nums[j] > nums[stack[-1]]:
                peek = stack.pop()
                key_2 = max(key_2, peek)
            stack.append(j)
        return max(key_2-key_1+1, 0)

思路3: 双指针
主要参考的题解链接
有一点绕,但是相对好理解。
在这里插入图片描述
在这里插入图片描述

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        n=len(nums)
        if n==1:
            return 0
        minn=nums[n-1]
        maxn=nums[0]
        right=left=0
        for j in range(n): # 从左侧更新它的最大值
            if nums[j]<maxn:
                right=j # right 是最后一个比前面所有值最大值小的位置
            maxn=max(maxn,nums[j])
        for j in range(n-1,-1,-1): #从右侧更新它的最小值
            if nums[j]>minn:
                left=j
            minn=min(minn,nums[j])
        # left和right分别是中间部分的左右边界
        if right==left:
            return 0
        return right-left+1

leetcode 901:股票价格跨度

题目描述:
编写一个 StockSpanner 类,它收集某些股票的每日报价,并返回该股票当日价格的跨度。

今天股票价格的跨度被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。

例如,如果未来7天股票的价格是 [100, 80, 60, 70, 60, 75, 85],那么股票跨度将是 [1, 1, 1, 2, 1, 4, 6]。

示例:
输入:[“StockSpanner”,“next”,“next”,“next”,“next”,“next”,“next”,“next”], [[],[100],[80],[60],[70],[60],[75],[85]]
输出:[null,1,1,1,2,1,4,6]
解释:
首先,初始化 S = StockSpanner(),然后:
S.next(100) 被调用并返回 1,
S.next(80) 被调用并返回 1,
S.next(60) 被调用并返回 1,
S.next(70) 被调用并返回 2,
S.next(60) 被调用并返回 1,
S.next(75) 被调用并返回 4,
S.next(85) 被调用并返回 6。

注意 (例如) S.next(75) 返回 4,因为截至今天的最后 4 个价格
(包括今天的价格 75) 小于或等于今天的价格。

提示:
调用 StockSpanner.next(int price) 时,将有 1 <= price <= 10^5。
每个测试用例最多可以调用 10000 次 StockSpanner.next。
在所有测试用例中,最多调用 150000 次 StockSpanner.next。
此问题的总时间限制减少了 50%。
通过次数25,882提交次数46,142

思路: 求比当天小的连续天数,想到单调栈
在本题中单调栈中存放两个值(股票价格,比这天小的连续天数)

class StockSpanner:

    def __init__(self):
        self.stack = []

    def next(self, price: int) -> int:
        k = 1
        while self.stack and self.stack[-1][0] <= price:
            k += self.stack[-1][1]
            self.stack.pop()
        self.stack.append((price, k))
        return k
        
# Your StockSpanner object will be instantiated and called as such:
# obj = StockSpanner()
# param_1 = obj.next(price)

leetcode 42: 接雨水

题目描述:
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:
在这里插入图片描述
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

示例 2:
输入:height = [4,2,0,3,2,5]
输出:9

提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105

解本题主要参考的题解链接
思路1:
分析可以接水的条件,就是知道当前位置的左右高度最大值,然后利用这个最大值减去自己的高度就是自己这个位置可以接到的水量。

class Solution:
    def trap(self, height: List[int]) -> int:
        # 超时
        res = 0
        for i in range(1, len(height)-1):
            max_z, maxy = 0, 0
            for z in range(0, i):
                max_z = max(max_z, height[z])
            for y in range(i+1, len(height), 1):
                maxy = max(maxy, height[y])
            res += max(min(max_z, maxy) - height[i], 0)
        return res

这样做会超时,进而引出使用动态规划的方式保存最大值,避免反复的搜索两边的最大值,一次搜索保存所有位置左右两侧的最大值。
时间复杂度:O(n^2),空间复杂度O(1)。

思路2: 动态规划记录两侧最大值

    def trap2(self, height: List[int]) -> int:
        res = 0
        dp_z, dp_y = [0] * len(height), [0]*len(height)
        for i in range(1, len(height)):
            dp_z[i] = max(dp_z[i-1], height[i-1])
        for j in range(len(height)-2, 0, -1):
            dp_y[j] = max(dp_y[j+1], height[j+1])
        # print(dp_z, dp_y)
        for k in range(1, len(height)-1):
            res += max(min(dp_z[k], dp_y[k])-height[k], 0)
        return res

时间复杂度:O(n), 空间复杂度O(n)。

思路3: 单调栈,分析一处的水量需要等到下一个比他高的位置出现才可以计算,这里参考的题解链接。
单调栈是一个递减栈,遇到一个比栈顶 cur大的 r ,就开始计算,高度是 r 和 cur的下一个元素 l 的较小值(因为左边也就是下一个元素是比cur大的)-cur的高度,宽度是 r-l-1,就是这段有多长。

    def trap3(self, height: List[int]) -> int:
        # 单调栈
        stack = []
        res = 0
        for i in range(0, len(height)):
            while stack and height[stack[-1]] < height[i]:
                cur = stack.pop()
                if not stack:
                    break
                l = stack[-1]
                res += ((i - l - 1) * (min(height[i], height[l]) - height[cur]))
            stack.append(i)
        return res

时间复杂度:O(n), 空间复杂度O(n)。

思路4: 双指针
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

class Solution:
    def trap(self, height: List[int]) -> int:
        left, right = 0, len(height)-1
        max_left, max_right = 0, 0
        ans = 0
        while left <= right:
            if max_left < max_right:
                ans += max(0, max_left-height[left])
                max_left = max(max_left, height[left])
                left += 1
            else:
                ans += max(0, max_right-height[right])
                max_right = max(max_right, height[right])
                right -= 1
        return ans

时间复杂度:O(n), 空间复杂度O(1)。

leetcode 84:柱状图中最大的矩形

题目描述:
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:
在这里插入图片描述
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:
在这里插入图片描述
输入: heights = [2,4]
输出: 4

提示:
1 <= heights.length <=105
0 <= heights[i] <= 104

思路: 单调栈
这题和42题接雨水很像,都是遇到下一个更矮的矩形,才知道当前的高度可以得到的矩形的面积;所以想到使用单调栈;
主要参考的题解链接
42和84是单调栈的常出题目
这里需要注意的一点就是要为数组在左右两边加上一个0,因为有些情况如果不加上两个哨兵点的话输出是不对的。
比如:[1, 2, 3]这样递增的栈没有遇到弹栈的情况,就无法得到一个结果,所以在后面加一个0;再比如[2, 1, 2]在右边添加了一个0之后变成[2, 1, 2, 0],栈的变化是[2]-[1]-[1, 2]-[1]-这是1和0进行比较,0小于1,对1进行弹栈,但是1可以确定的宽度不是2,而是3,造成这种错误的原因是之前弹出了第一个2但是我们却没有记忆,所以在最开始放置一个0,这样每次我们就去cur元素左边元素+1的位置就是要计算的宽度了,具体的见代码:

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        maxx = 0
        stack = []
        heights = [0] + heights
        heights.append(0)
        for i in range(len(heights)):
            while stack and heights[stack[-1]] > heights[i]:
                peek = stack.pop()
                left = stack[-1]
                maxx = max(maxx, (i - left - 1) * heights[peek])
            stack.append(i)
        return maxx
详解单调栈算法 栈属于基础数据结构之一,基础到仅用「后进先出」这四个字即可完整概括其核心特征。然而,基础并不代表着简单,「后进先出」的背后反而隐藏着多样的变化与极其广泛的应用。 在本篇文章中,我们将针对在基础栈上稍加改动所形成的「单调栈」算法进行详解。该算法与「单调队列」组成了算法题中最常考察的线性数据结构,属于面试中必知必会的算法知识。 阅读详情

相关推荐

基于多时间尺度的电动汽车光伏充电站联合分层优化调度(Matlab代码实现)

该研究提出了一种电动汽车光伏充电站的分层优化调度方法,采用日前-日内两阶段协同优化框架。日前阶段通过混合整数规划对多充电站进行全局优化,以平抑电网波动和降低购电成本为目标;日内阶段基于实时数据,采用NSGA-II等算法动态分配充电功率。该方法实现了光伏高效消纳、成本节约和电网负荷平衡的有效统一。

zhangxd212489的博客 519

算法学习小结

1、最短无序连续子数组 给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。 输入:nums = [2,6,4,8,10,9,15] 输出:5 解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。 解题思路:O(n) 从左往右找到第一个降序点,从这个点开始找到最大的元素max。 从右往左找到第一个升序点,从这个点开始找到最小的元素min。 从左往右遍历,第一个大于min的元素即是失序数组

kwsunnh的博客 1592

SEG-Y 数据介绍及读写

无

1万+

单调栈:最短无序连续子数组

最短无序连续子数组 问题: 1.排序法( O(nlogn)) 思路: 建立一个新数组,其元素为原数组的升序排列,比较两数组,得到第一个和最后一个不匹配的元素,它们都需重新排列,且是子数组的边界 代码: class Solution { public: int findUnsortedSubarray(vector<int>& nums) { int n...

qq_44709990的博客 413

基于STM32的超声波流量计设计

本项目基于STM32微控制器设计了一种超声波流量计,采用时间差法测量液体或气体的流速,计算流量并通过显示屏实时显示,同时支持远程数据传输。本设计通过STM32微控制器实现了基于时间差法的超声波流量计,集成了超声波信号采集、流量计算、状态显示和远程通信功能。本系统需要实现超声波信号的实时采集与处理,计算流速和流量,并将数据通过OLED显示和无线模块上传。系统需具备高精度的时间测量能力和良好的抗干扰能力。通过计算超声波在顺流和逆流方向上的传播时间差,结合管道直径与流体特性,计算流速并进一步计算流量。

stm32d1219的博客 2349

uni-app蓝牙MTU设置失效探因:从20字节限制到跨设备兼容性实战

本文深入探讨了uni-app蓝牙开发中MTU设置失效的常见问题,特别是20字节限制的成因及解决方案。通过分析设备兼容性、蓝牙协议栈特性和系统版本差异,提供了智能延迟策略、设备特征检测和渐进式MTU提升等实战方案,帮助开发者优化蓝牙数据传输效率。

weixin_29289821的博客 288

leetcode 581. 最短无序连续子数组(详解普通 / 进阶 / 单调栈解法,Java版)

题目 题解 方法1(暴力排序):时间复杂度O(nlogn),空间复杂度O(n) 一个简单的想法是:将数组 nums 进行排序,记为 nums_sorted 。然后比较 nums 和 nums_sorted 的元素来决定最左边和最右边不匹配的元素。它们之间的子数组就是要求的最短无序子数组。 public int findUnsortedSubarray(int[] nums) { int[] snums = nums.clone(); Arrays.sort(snums); int

寒泉 6万+

Windows系统的Mamba环境配置详细教程(状态空间模型)

causal_conv1d也是安装mamba的依赖必须库。安装完成后,通过pip list可以查看到安装的库。Triton是安装mamba的依赖,需要先安装。上述工作准备好后,按下面步骤安装。直接根据离线文件安装即可。是自己的虚拟环境名字。

2301_77831163的博客 3677

【算法】【单调栈】使用双单调栈,解决力扣2866. 美丽塔 II

本文介绍了一种使用双单调栈解决力扣 2866 题《美丽塔 II》的算法。该算法旨在找到满足一定条件的美丽塔方案,其中美丽塔的定义涉及到山脉数组的特性。文章采用 C++ 实现,并通过详细的注释解释了每个步骤的原理和实现方式。

未来就在脚下。 700

【毕业设计参考】基于yolov8+pyqt5自适应界面设计的锂电池表面缺陷检测系统

基于YOLOv8+PyQt5的锂电池表面缺陷检测系统结合了先进的目标检测技术与友好的用户界面设计,为锂电池质量检测提供了一种高效、准确的解决方案。未来,随着深度学习技术的不断发展,我们可以进一步优化模型,提高检测精度和速度,同时拓展系统功能,如实现实时视频流检测、与生产系统的深度集成等,为锂电池产业的发展注入新的活力。希望本文对大家在相关领域的研究和实践有所帮助,欢迎大家在评论区交流讨论。

1182

OTFS 消息传递算法信号检测【附matlab代码详解】

OTFS 消息传递算法方面的一些浅浅理解。

Cuby的博客 4011

单调栈类题目专题训练 -- LeetCode上5道与单调栈相关的题

这个专题中的题目是我跟随代码随想录的刷题计划,在LeetCode上做的与单调栈相关的题目,用于加深对单调栈的理解! 下面的内容将会有每一道题目的题意、在代码随想录中对应的参考文章、我的思路以及我所写的Java代码,希望对你有帮助! 目录1 - LeetCode 739 每日温度2 - LeetCode 496 下一个更大元素 I3 - LeetCode 503 下一个更大元素 II4 - LeetCode 42 接雨水5 - LeetCode 84 柱状图中最大的矩形     1 -

今天你学习了吗? 8196

Plant Simulation 快速建模与布局(3)——自动生成的对象 代码“安全”删除管理

《PlantSimulation快速布局建模课程》教授利用SimTalk语言实现高效建模的技术要点,包括批量对象创建、阵列布局、属性管理及自动连接功能。重点讲解对象安全删除机制,通过existsObject检查对象存在性后使用deleteObject方法删除,避免程序报错。课程提供完整代码示例,展示如何通过循环结构实现矩阵布局对象的创建与安全删除,确保代码健壮性,显著提升建模效率。

qq_31964455的博客 119

LeetCode——503. 下一个更大元素 II(单调栈)

文章目录503. 下一个更大元素 II(单调栈)题目**思路**(单调栈代码框架)代码** 503. 下一个更大元素 II(单调栈) 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/next-greater-element-ii 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 题目** 给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这

李霁明的博客 546

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

leetcode单调栈总结

本次主要总结利用单调栈解决leetcode中的第739题每日温度、第496题下一个更大的元素I、第503题下一个更大的元素II。 单调栈主要解决的几种问题: 比当前元素更大的下一个元素 比当前元素更大的前一个元素 比当前元素更小的下一个元素 比当前元素更小的前一个元素 需要思考的几个问题: 如何操作单调栈 严格单调栈还是非严格单调栈 单调递增栈还是单调递减栈 先以739题为例看看如何操作单...

小可爱的博客 1001

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

leetcode经典题目——单调栈

本文总结了力扣中5道典型的单调栈应用题目,包括739.每日温度、496.下一个更大元素I、503.下一个更大元素II、42.接雨水和84.柱状图中最大的矩形。这些题目都利用了单调栈的特性,通过维护一个单调递减或递增的栈结构来高效解决问题。解题核心在于: 维护栈的单调性; 在遍历过程中处理栈顶元素与当前元素的关系; 通过下标差计算相关指标。单调栈的时间复杂度通常为O(n),空间复杂度为O(n),能高效解决寻找下一个更大/更小元素、计算面积或容量等问题。对于循环数组问题(如503题),可通过遍历两次的方式处理。

2301_80275666的博客 989

算法学习——LeetCode力扣单调栈篇(739. 每日温度、496. 下一个更大元素 I、503. 下一个更大元素 II、42. 接雨水、84. 柱状图中最大的矩形)

算法学习——LeetCode力扣单调栈篇(739. 每日温度、496. 下一个更大元素 I、503. 下一个更大元素 II、42. 接雨水、84. 柱状图中最大的矩形)

拉依达不拉跨的博客 1358

算法打卡day51|单调栈篇02| Leetcode 503.下一个更大元素II、42. 接雨水

JAVA算法|单调栈篇02| Leetcode 503.下一个更大元素II、42. 接雨水

改变从现在开始 1016

力扣labuladong一刷day50天单调栈

单调栈就这一类特殊题目,一个扳手对应一个螺丝,把模板给记牢了即可。

qq_43511039的博客 953

单调栈学习C++

单调递增或者递减。

2401_82677021的博客 1284

leetcode刷题-单调栈

本题本质还是对nums2采用单调栈的算法计算下一个最大元素,但是返回的result需要和nums1大小一致,顺序一致,因此对nums2中的元素计算完后需要映射回nums1,除此之外,本题的result数组应该初始化为-1。这里可以借助单调栈的特性,栈内的元素是单调递增的,因此在获得了某一个元素的右边第一个比它大的元素,那么栈里的下一个元素就是左边第一个比它大的元素。此处的单调栈是单调递减的,因为要找左边和右边第一个比它小的,中间就是大于等于它的,高度就是当前柱子的高度,宽度为中间柱子的宽度;

emmmmXxxy的博客 1208

力扣 503:下一个更大元素 II - 循环数组的单调栈解法

大家好!今天我们来复盘一道经典的 LeetCode 题目:503. 下一个更大元素 II。这道题是 “下一个更大元素” 问题的进阶版,因为它引入了一个特殊的概念:循环数组。 作为一名新手,我们可能首先会想到最直观的暴力解法,然后发现它效率低下。别担心,这是一个正常的思维过程。正是通过这种思考,我们才能更好地理解和掌握更高效的算法——单调栈。 接下来,我将带你从零开始,一步步理清这道题的解题思路,并深入对比两种方法,让你彻底吃透它!

2401_83653239的博客 721

LeetCode 503. 下一个更大元素 II(单调栈)

文章目录1. 题目2. 解题2.1 朴素解法2.2 单调栈解题 1. 题目 给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。 示例 1: 输入: [1,2,1] 输出: [2,-1,2] 解释: 第一个...

Michael是个半路程序员 1160

【Leetcode】单调栈

单调栈是一种高效的栈结构,常用来解决数组中元素顺序相关的问题,如“下一个更大元素”等。其核心思想是通过维护栈内元素的单调性,并记录元素的间顺序关系,以减少不必要的比较操作。通常情况下,由于每个元素入栈和出栈各一次,时间复杂度为 O(n)。

冰可乐的数据之路 747

leetcode(力扣)单调栈题目解析记录(python版本)

其次,根据单调栈的特点,不难发现height[idx]小于height[stack[-1]]和height[i],通俗来讲就是出现一个坑,可以接雨水。上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。商品 1 的价格为 price[1]=4 ,你将得到 prices[3]=2 的折扣,所以最终价格为 4 - 2 = 2。while stack and nums[i]

maggieyiyi的博客 772

leetcode 503.下一个更大元素II 单调栈

代码】leetcode 503.下一个更大元素II 单调栈。

Alkali!的博客 454
上一篇: 单调栈 I:leetcode 739、402、316、321
下一篇: leetcode 93: 复原IP地址 (面试常考)
coding_diamond
博客等级 码龄8年 8粉丝 131原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值