首页 > 编程语言 >单调栈算法模板

单调栈算法模板

时间:2023-07-28 23:08:25浏览次数:44  
标签:nums pos len height 算法 模板 heights stack 单调

单调栈模板:

单调栈模板:

for (遍历这个数组)
    while (栈不为空 && 栈顶元素<或者>当前元素)
		栈顶元素出栈
		更新结果
		
    当前数据入栈


例如单调递增的stack,python实现就是:	
stack = []	
for i in range(0, len(arr)):
	while stack and stack[-1] > arr[i]: 
		stack.pop()
		# do something to find result 常用要结合stack pop的元素和i的位置,更有甚者还要看栈顶也就是stack[-1]来综合计算
	
	stack.append(arr[i])

 

变种:单调队列,见:  

84. 柱状图中最大的矩形

https://leetcode.cn/problems/largest-rectangle-in-histogram/ 

难度困难2265收藏分享切换为英文接收动态反馈

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

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

 

示例 1:

单调栈算法模板_List

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:

单调栈算法模板_算法_02

输入: heights = [2,4]
输出: 4

 

提示:

  • 1 <= heights.length <=105
  • 0 <= heights[i] <= 104

 

class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        heights = [0] + heights + [0]
        ans = 0
        stack = []
        for i in range(0, len(heights)):
            while stack and heights[stack[-1]] > heights[i]:
                pos = stack.pop()
                square = heights[pos] * (i - 1 - stack[-1] )
                # print(heights[pos], i, stack[-1], square)
                ans = max(ans, square)

            stack.append(i)
        
        return ans

  

为啥是(i - 1 - stack[-1] )?而不是 i - pos?

(1)对于正常情形:只需要向右边跨越的矩形面积,例如下图数组下标2对应的元素5,其对应的矩形面积是10,只需要跨2个格子,只有右边的格子比它高,所以只能往右跨越。

计算方法:单调栈里是[1,5,6],遇到2的时候,应该从单调栈里pop 6和5,而pop 5的时候,就可以计算高度为5的最大面积 = 5(高度) x 2(宽度,等于元素2的下标 - 元素4的下标,也等于元素2的下标 - 1 - 元素1的下标),如下图所示:

单调栈算法模板_算法_03

 

向左跨越了1个格子,加上自己的1个格子,一共6个。对于这种场景,我们看看stack里的数据情况,stack=[0,1],遇到的元素是0,则在pop 1的时候,宽度如何计算呢?见下第二个图说明!

 

单调栈算法模板_数组_04

 

 

单调栈算法模板_算法_05

 

要向左去跨越第一个比它矮小的格子!所以就只能是stack pop本身以后,再取栈顶元素就是正好比它小的格子了。

 

42. 接雨水

https://leetcode.cn/problems/trapping-rain-water/

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

 

示例 1:

单调栈算法模板_算法_06

 

 

输入: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

 

class Solution:
    def trap(self, height: List[int]) -> int: 
        stack = []	
        ans = 0
        for i in range(0, len(height)):
            while stack and height[stack[-1]] < height[i]: 
                pos = stack.pop()

                if not stack: # 前面没有东西了,表明全是上升的格子
                    continue

                w = i - stack[-1] - 1
                h = min(height[i], height[stack[-1]]) - height[pos]
                water = w * h     # 物理含义:height[pos]和height[i], height[stack[-1]]三根柱子能够积蓄的水
                ans += water
                
            stack.append(i)

        return ans

 

物理含义:water = w * h 如下图所示:

 

 

单调栈算法模板_算法_07

 

 

  

 

52 · 下一个排列【不使用stack也可以】

给定一个整数数组来表示排列,按升序找出其下一个排列。

排列中可能包含重复的整数

样例

样例 1:

输入:

数组 = [1]

输出:

[1]

解释:

只有一个整数,下一个排列是自己。

样例 2:

输入:

数组 = [1,3,2,3]

输出:

[1,3,3,2]

解释:

[1,3,2,3]的下一个排列是[1,3,3,2]。

样例 3:

输入:

数组 = [4,3,2,1]

输出:

[1,2,3,4]

解释:

没有字典序更大的排列时,输出字典序最小的排列。

 最近的解法:

class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        def find_swap_pos():
            i = len(nums) - 1
            while i - 1 >= 0 and nums[i] <= nums[i - 1]:
                i -= 1

            return i - 1

        def find_swap_pos2(pos):
            j = pos + 1
            while j < len(nums) and nums[j] > nums[pos]:
                j += 1

            return j - 1

        def swap(m, n):
            while m < n:
                nums[m], nums[n] = nums[n], nums[m]
                n -= 1
                m += 1

        pos = find_swap_pos()
        if pos < 0:
            swap(0, len(nums) - 1)
            return
        
        pos2 = find_swap_pos2(pos)
        nums[pos], nums[pos2] = nums[pos2], nums[pos]
        swap(pos + 1, len(nums) - 1)

  

 使用stack写的话:

from typing import (
    List,
)

class Solution:
    """
    @param nums: A list of integers
    @return: A list of integers
    """
    def next_permutation(self, nums: List[int]) -> List[int]:
        # write your code here
        # 123213 4510 ==> 123213 5014
        # 123213 476410 ==> 123213 601447
        # 考察单调栈,三步:
        # 1、从后向前升序,找到第一个降序数字,对于123213 476410则找到4是第一个降序数字
        # 2、然后找到升序里第一个大于它的数字,就是6了!
        # 3、然后交换4和6,则变成123213 674410,最后将74410反转下排序就是123213 601447
        if not nums or len(nums) == 1:
            return nums

        i = len(nums) - 2
        stack = [len(nums)-1]
        while i >= 0 and stack and nums[stack[-1]] <= nums[i]:
            stack.append(i)
            i -= 1

        if i < 0:
            return nums[::-1]

        # assert nums[i] < stack[-1]
        pos1 = pos2 = i
        while stack and nums[stack[-1]] > nums[i]:
            pos2 = stack.pop()

        nums[pos1], nums[pos2] = nums[pos2], nums[pos1]
        i, j = pos1+1, len(nums)-1
        while i < j:
            nums[i], nums[j] = nums[j], nums[i] 
            i += 1
            j -= 1      

        return nums

 

标签:nums,pos,len,height,算法,模板,heights,stack,单调
From: https://blog.51cto.com/u_11908275/6888018

相关文章

  • 算法编程中的Word 四兄弟 Word Break , Word Ladder, Word Search, Word Pattern
    Word四兄弟WordBreak,WordLadder,WordSearch,WordPattern,太容易出现了,针对性分析下。  829·字模式II算法困难通过率47% 描述给定一个pattern和一个字符串str,查找str是否遵循相同的模式。这里遵循的意思是一个完整的匹配,在一个字母的模式和一个非空的单词str之间......
  • 单调栈
    定义具有单调性的栈结构,该数据结构的目的是快速找到与一个元素距离最近的元素过程(摘自oiwiki)插入将一个元素插入单调栈时,为了维护栈的单调性,需要在保证将该元素插入到栈顶后整个栈满足单调性的前提下弹出最少的元素。例如,栈中自顶向下的元素为{0,11,45,81}。插入元素14......
  • 文心一言 VS 讯飞星火 VS chatgpt (67)-- 算法导论6.5 6题
    文心一言VS讯飞星火VSchatgpt(67)--算法导论6.56题六、在HEAP-INCREASE-KEY的第5行的交换操作中,一般需要通过三次赋值来完成。想一想如何利用INSERTION-SORT内循环部分的思想,只用一次赋值就完成这一交换操作?文心一言:在HEAP-INCREASE-KEY的第5行交换操作中,我们可以通......
  • JavaScript学习 -- HMAC算法基本原理
    HMAC(Hash-basedMessageAuthenticationCode)算法是一种基于哈希算法的消息认证码算法。它可以用于验证和保护数据在传输过程中的完整性和真实性。在JavaScript中,我们可以使用HMAC算法来保证数据的安全性。本篇文章将介绍HMAC算法的基本原理和相关技术,并提供一些实例来演示如何在Ja......
  • 【模板】三维偏序(陌上花开)
    P3810【模板】三维偏序(陌上花开)考虑CDQ分治。考虑简单情况。一维偏序,排序即可,复杂度\(O(n\logn)\)。二维偏序,排序后使用树状数组离散化后维护(参考逆序对,特点是已经将第一维排序过了)。二维偏序,排序后使用归并排序(参考逆序对,特点是已经将第一维排序过了)。考虑三维偏序,......
  • LeetCode 239. Sliding Window Maximum 单调队列
    Youaregivenanarrayofintegersnums,thereisaslidingwindowofsizekwhichismovingfromtheveryleftofthearraytotheveryright.Youcanonlyseetheknumbersinthewindow.Eachtimetheslidingwindowmovesrightbyoneposition.Return......
  • 代码随想录算法训练营第三天| LeetCode 203.移除链表元素(同时也对整个单链表进行增删
    203.移除链表元素      题目链接/文章讲解/视频讲解::https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html    卡哥题目建议:本题最关键是要理解虚拟头结点的使用技巧,这个对链表题目很重要。   做题思路:   ......
  • 【算法】哈希学习笔记
    1.哈希(hash)简介1.1前言又来写算法总结了qwq。今天是2023/7/8,期末考试已经考完了。初二下注定是一个煎熬的学期,所以我在这一学期并没有学什么新算法,OI也没什么长进。但倒是深造了几个算法,比如:dp,hash,线段树。之前一直想写一篇hash的学习笔记,但由于种种原因,并没有写成。于......
  • 八大排序算法
    1.冒泡排序排序原理:数组元素两两比较,交换位置,大元素往后放,那么经过一轮比较后,最大的元素,就会出现在最大素引处。/***@description冒泡排序*@author:PeiChen*@version1.0*/publicclassBubbleSort{publicstaticvoidmain(String[]args){int[]a......
  • 学生个人网页设计作品 学生个人网页模板 简单个人主页成品 个人网页制作 HTML学生个人
    HTML网页作业期末学生结课大作业作品(HTML+CSS+JS),都是给学生定制的都符合学校或者学生考试期末作业的水平,都是div+css框架原创代码写的,有的有js,有的视频+音乐+flash的等元素的插入…2000多例HTML5期末考核大作业源码都可满足大学生网页大作业网页设计作业需求,喜欢的可以下载!网......