首页 > 编程语言 >算法思想——单调栈及其运用实例

算法思想——单调栈及其运用实例

时间:2024-10-16 20:19:35浏览次数:9  
标签:int 元素 算法 实例 数组 new stack 单调

单调栈的定义

单调栈是一种数据结构,它维护了一个元素序列,这个序列在栈内要么单调递增,要么单调递减。在单调栈中,新元素的插入操作会遵循特定的规则:对于单调递增栈,只有当新元素大于或等于栈顶元素时,才能将其压入栈中;对于单调递减栈,则相反,只有当新元素小于或等于栈顶元素时,才能将其压入栈中。这种结构保证了栈内的元素顺序在某种意义上是有序的,从而支持高效的元素插入和查询操作。

单调递增栈

单调递增栈是一种特殊类型的栈,它只允许栈内的元素按照严格递增的顺序排列。在这种栈中,每次新元素被压入栈时,必须满足这个元素大于或等于栈顶的元素。如果新元素不满足这个条件,它将不会被压入栈中。这种栈的使用保证了,从栈顶到栈底,元素的值是单调递增的,即每个元素都大于或等于它下面的所有元素。

单调递增栈常用于处理数组中的元素,以找到特定的序列或模式,例如查找给定数组中每个元素右侧第一个比它大的元素,或者左侧第一个比它小的元素。通过利用单调递增栈的性质,可以在一次遍历中高效地解决这类问题。
下面以一个数组案例来解释单调递增栈的入栈出栈的过程:
739. 每日温度查找比数组元素大的下一个数组元素的下标,栈内元素记录的是前一句的结果。
数组元素为[73,74,75,71,69,72,76,73]

第i步数组元素栈内元素记录数组元素大的下一个数组元素的下标
17300,0,0,0,0,0,0,0
27411,0,0,0,0,0,0,0
37521,1,0,0,0,0,0,0
4712,31,1,0,0,0,0,0,0
5692,3,41,1,0,0,0,0,0,0
6722,3,51,1,0,0,1,0,0,0
7723 ,51,1,0,2,1,0,0,0
8765,61,1,4,2,1,0,0,0
97661,1,4,2,1,1,0,0
10736,71,1,4,2,1,1,0,0

下面是步骤2的图示
单调栈入栈出栈过程

单调递减栈

单调递减栈是一种特殊类型的栈,它确保栈内的元素按照严格递减的顺序排列。在这个栈中,每次新元素被压入栈时,必须满足这个元素小于或等于栈顶的元素。如果新元素不满足这个条件,它将不会被压入栈中。这种栈的使用保证了,从栈顶到栈底,元素的值是单调递减的,即每个元素都小于或等于它下面的所有元素。

压栈和出栈过程和上面单调递增栈类似,这里不再赘述!!!
下面写了几道力扣题,方面大家理解:
739. 每日温度

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int[] arr=new int[temperatures.length];
        Stack<Integer> st= new Stack<>();
        for(int i=0;i<temperatures.length;i++){
            int t=temperatures[i];
            while(!st.isEmpty()&&t>temperatures[st.peek()]){
                int j=st.pop();
                arr[j]=i-j;
            }
            st.push(i);
        }
        return arr;
    }
}

这个就是应用单调栈存储比下一个元素大的数组下标,具体的解题过程上面已经给出。
496. 下一个更大元素 I

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
         Stack<Integer> stack = new Stack<Integer>();
        HashMap<Integer, Integer> hasMap = new HashMap<Integer, Integer>();
        int[] result = new int[nums1.length];
        for(int num : nums2) {
            while(!stack.isEmpty() && stack.peek()<num){
                hasMap.put(stack.pop(), num);
            }
            stack.push(num);
        }
        for(int i = 0; i < nums1.length; i++) result[i] = hasMap.getOrDefault(nums1[i], -1);      
        return result;
    }
}

和上一题的解法一样
1475. 商品折扣后的最终价格

class Solution {
    public int[] finalPrices(int[] prices) {
          int[] arr = new int[prices.length];
        ArrayDeque<Pair<Integer, Integer>> stack = new ArrayDeque<>();
        for (int i = 0; i <= prices.length; i++) {
            int price = i == prices.length ? 0 : prices[i];
            while (!stack.isEmpty() && stack.peekLast().getKey() >= price) {
                Pair<Integer, Integer> pair = stack.removeLast();
                arr[pair.getValue()] = pair.getKey() - price;
            }
            stack.addLast(new Pair<Integer, Integer>(price, i));
        }
        return arr;
    }
}

503. 下一个更大元素 II

class Solution {
    public int[] nextGreaterElements(int[] nums) {
       int n = nums.length;
        int[] sum = new int[n];
        Arrays.fill(sum, -1);
      Deque<Integer> stack = new LinkedList<Integer>();
        for (int i = 0; i < n * 2 - 1; i++) {
            while (!stack.isEmpty() && nums[stack.peek()] < nums[i%n]) {
                sum[stack.pop()] = nums[i % n];
            }
            stack.push(i%n);
        }
        return sum;
    }
}

循环查找的话,加一个取余操作进行查找
962. 最大宽度坡

class Solution {
    public int maxWidthRamp(int[] nums) {
        int num= 0;
        int n = nums.length;
        Stack<Integer>min = new Stack<>();
        min.push(0);
        for(int i = 0; i < n; i ++){
            if(nums[i] < nums[min.peek()])min.push(i);
        }
        for(int i = n - 1; i >= 0; i --){
            while(!min.isEmpty() && nums[min.peek()] <= nums[i]){
                num= Math.max(res,i - min.peek());
                min.pop();
            }
        }
        return num;
    }
}

不断遍历找到下标相差最大的值。
853. 车队

class Solution {
    public int carFleet(int target, int[] position, int[] speed) {
        //上同下小数组大,上同下大数组小,上大下小数组大,上小下大数组小
        double[] time=new double[target];
        for(int i=0;i<position.length;i++){
            time[position[i]]=(target-position[i])/(double)speed[i];
        }
        Deque<Double> stack = new ArrayDeque<>();
        for(int i=0;i<target;i++){
            if(time[i]>0){
                while(!stack.isEmpty()&&time[i]>=stack.peek()){//保证数组中元素从底到顶递减
                    stack.pop();
                }
                stack.push(time[i]);
            }
        }
        return stack.size();
    }
}

标签:int,元素,算法,实例,数组,new,stack,单调
From: https://blog.csdn.net/w287586/article/details/142936283

相关文章

  • 《php经典实例》5 第五章 变量
    7把复杂的数据类型压缩到一个字符串中7.2magic_quotes_gpc魔术引号开关7.2.1魔术引号开关的功能:如果输入的数据有单引号'、双引号"、反斜杠\ 、会自动加上反斜杠,以防sql注入等恶意代码7.2.2开启此功能在php.ini中设置magic_quotes_gpc=On此功能仅在在<=......
  • 【C++】精妙的哈希算法
    ......
  • 大模型量化算法之Smoothquant
    SmoothQuant:AccurateandEfficientPost-TrainingQuantizationforLargeLanguageModels发表于ICML20238-bitweight,8-bitactivation(W8A8)训练后量化方法(PTQ)量化的部分是线性层以及矩阵乘法,LayerNorm以及Softmax还是以更高精度的半精度浮点数F......
  • Javascript算法——二分查找
    1.数组1.1二分查找1.搜索索引开闭matters!!![left,right]与[left,right)/***@param{number[]}nums*@param{number}target*@return{number}*/varsearch=function(nums,target){letleft=0;letright=nums.length-1;//[left,right],相等时......
  • leetcode算法题 437.路径总和
    题目描述给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。 示例示例1:输入:root=[10,5,-3,3,2,null,1......
  • 算法iITCGP的数值试验结果
    试验一:试验二: ......
  • 算法-中缀转后缀表达式(C++)
    因为操作数在后缀表达式中它们的顺序与中缀表达式一致,所以操作数不需要进行特殊处理,所以遇到数字就输出,遇到符号就经过处理再输出所以需要用一个存储结构存符号为什么用栈存储:要利用后进先出的特性出栈也就是加入到后缀表达式中,一部分一部分处理,处理完一部分,要处理他邻近的......
  • <Leetcode:算法题及解析>最大子数组和(Javascript版)
    题目描述:给你一个整数数组nums,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。本题可以使用Kadane's算法实现,这是一种用于解决最大子数组和问题的高效算法。它由JosephBornKadane在1984年提出。这个算法的核......
  • ssm果蔬销售商城vue 协同过滤算法 echart可视化springboot
    目录项目介绍系统实现截图协同过滤算法B/S架构技术介绍核心代码部分展示论文结构其他springboot项目推荐系统测试详细视频演示果蔬销售商城源码获取项目介绍ssm果蔬销售商城果蔬销售系统—便于商家记录销售情况同时方便消费者购买水果蔬菜的电商平台前台用户模块:......
  • 智能车摄像头开源—1.2核心算法:自适应八向迷宫(下)
    一、前言     本篇将详细讲述自适应八向迷宫的算法原理,优势以及弊端。     同样在此声明:此系列开源均由本人实践和经验得出,并不保证完全正确,仅供参考和入门学习。二、自适应八向迷宫优势具备极快的速度优势,在双核主频200MHz英飞凌TC264主控上,单核运算......