力扣刷题小记9(单调栈)

本文是博主关于在力扣平台刷题的总结,重点介绍了单调栈在解题中的应用,包括每日温度、下一个更大元素、接雨水和柱状图中最大矩形等问题的思路和题解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

博主个人博客网站:文客
这个系列主要记录在力扣刷题的总结和问题
如果你想每天和我一起刷题,可以关注一下我的个人博客网站:文客,我会每天在这里更新技术文章和面试题,也会及时收到大家的评论与留言,欢迎各位大佬来交流!

739. 每日温度

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指在第 i 天之后,才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例 1:

输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]

示例 2:

输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]

示例 3:

输入: temperatures = [30,60,90]
输出: [1,1,0]

思路:

使用单调栈,我们在程序中维护一个栈,这个栈存储温度数组的下标,而且栈顶到栈尾是递增的,当遇到比栈顶大的元素时就代表遇见了第一个更高的温度,根据下标差值计算天数即可,将结果存储在res数组中

题解:

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int[] res = new int[temperatures.length];
        Stack<Integer> stack = new Stack<>();
        stack.push(0);
        for(int i = 1; i < temperatures.length; i++){
            if(temperatures[i] <= temperatures[stack.peek()]){
                stack.push(i);
            } else {
                while(!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]){
                    res[stack.peek()] = i - stack.peek();
                    stack.pop(); 
                }
                stack.push(i);
            }
        }
        return res;
    }
}

496. 下一个更大元素 I

nums1 中数字 x下一个更大元素 是指 xnums2 中对应位置 右侧第一个x 大的元素。

给你两个 没有重复元素 的数组 nums1nums2 ,下标从 0 开始计数,其中nums1nums2 的子集。

对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j]下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1

返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素

示例 1:

输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
- 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
- 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。

示例 2:

输入:nums1 = [2,4], nums2 = [1,2,3,4].
输出:[3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 2 ,用加粗斜体标识,nums2 = [1,2,3,4]。下一个更大元素是 3 。
- 4 ,用加粗斜体标识,nums2 = [1,2,3,4]。不存在下一个更大元素,所以答案是 -1 。

思路:

维护一个单调栈,因为nums1是nums2的子集,所以我们遍历nums2,利用单调栈的特性求出nums2中每个元素的下一个更大元素,用map存储结果,最后再遍历nums1赋予结果

题解:

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

503. 下一个更大元素 II

给定一个循环数组 numsnums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素

数字 x下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1

示例 1:

输入: nums = [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

示例 2:

输入: nums = [1,2,3,4,3]
输出: [2,3,4,-1,4]

思路:

循环数组一般就开二倍长度的数组,收尾相接,然后维护一个单调栈即可

题解:

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

42. 接雨水

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

示例 1:

img

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

思路1(双指针):

遍历height数组,每遍历到一个元素时,分别向左向右寻找最高的高度,然后用左右最高高度的最小值减去当前高度,就是当前高度可以接的雨水。

题解1(双指针):

class Solution {
    public int trap(int[] height) {
        int res = 0;
        for(int i = 0; i < height.length; i++){
            int lHeight = height[i];
            int rHeight = height[i];
            for(int l = i - 1; l >= 0; l--){
                if(height[l] > lHeight){
                    lHeight = height[l];
                }
            }
            for(int r = i + 1; r < height.length; r++){
                if(height[r] > rHeight){
                    rHeight = height[r];
                }
            }
            int t = Math.min(rHeight,lHeight) - height[i];
            res += t;
            
        }
        return res;
    }
}

思路2(动态规划):

动态规划是双指针解法的优化版本,也是对每个高度求出左边最高和右边最高,后面的思路都是一样的

题解2(动态规划):

class Solution {
    public int trap(int[] height) {
        int res = 0;
        int[] dp1 = new int[height.length];
        int[] dp2 = new int[height.length];
        dp1[0] = height[0];
        for(int i = 1; i < height.length; i++){
            dp1[i] = Math.max(dp1[i - 1], height[i]);
        }
        dp2[height.length - 1] = height[height.length - 1];
        for(int i = height.length - 2; i >= 0; i--){
            dp2[i] = Math.max(dp2[i + 1], height[i]);
        }
        for(int i = 0; i < height.length; i++){
            res += Math.min(dp1[i],dp2[i]) - height[i];
        }
        return res;
    }
}

思路3(单调栈):

维护一个单调栈,这个栈从栈头到栈尾是单调递增的,这样遇到更大的高度时,才会出现凹槽。

题解3(单调栈):

class Solution {
    public int trap(int[] height) {
        int res = 0;
        Stack<Integer> stack = new Stack<>();
        int[] temp = new int[height.length + 2];
        temp[0] = 0;
        temp[temp.length - 1] = 0;
        for(int i = 1; i < temp.length - 1; i++){
            temp[i] = height[i - 1];
        }
        stack.push(0);
        for(int i = 1; i < temp.length; i++){
            if(temp[i] < temp[stack.peek()]){
                stack.push(i);
            } else if(temp[i] == temp[stack.peek()]){
                stack.push(i);
            } else {
                while(!stack.isEmpty() && temp[i] > temp[stack.peek()]){
                    int mid = stack.pop();
                    if(!stack.isEmpty()){
                        int left = stack.peek();
                        int t = (Math.min(temp[i],temp[left]) - temp[mid]) * (i - left - 1);
                        res += (t > 0) ? t : 0;
                    }
                }
                stack.push(i);
            }
        }
        return res;
    }
}

84. 柱状图中最大的矩形

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

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

示例 1:

img

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

示例 2:

img

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

思路:

维护一个单调栈,栈头到栈尾是单调递减的,遇到下一个更小的元素就可以计算当前的最大面积

题解:

class Solution {
    public int largestRectangleArea(int[] heights) {
        int largestArea = 0;
        int[] temp = new int[heights.length + 2];
        temp[0] = 0;
        temp[temp.length - 1] = 0;
        for(int i = 1; i < temp.length - 1; i++){
            temp[i] = heights[i - 1];
        }
        Stack<Integer> stack = new Stack<>();
        stack.push(0);
        for(int i = 1; i < temp.length; i++){
            while(!stack.isEmpty() && temp[i] < temp[stack.peek()]){
                int h = temp[stack.pop()];
                largestArea = Math.max(largestArea,h * (i - stack.peek() - 1));
            }
            stack.push(i);
        }
        return largestArea;
    }
}

博客原文地址

力扣刷题小记9(单调栈)
在这里插入图片描述

好的,关于力扣C++常用操作,我可以给你一些常见的操作和技巧: 1. 使用 STL 容器和算法库:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,包含了许多常用的容器和算法。在力扣中,使用 STL 可以大大提高代码的效率和可读性。例如,vector 可以用来存储动态数组,sort 可以用来排序等等。 2. 使用 auto 关键字:auto 关键字可以自动推导变量类型,可以减少代码量和提高可读性。例如,auto x = 1; 可以自动推导出 x 的类型为 int。 3. 使用 lambda 表达式:lambda 表达式是 C++11 中引入的一种匿名函数,可以方便地定义一些简单的函数对象。在力扣中,使用 lambda 表达式可以简化代码,例如在 sort 函数中自定义比较函数。 4. 使用位运算:位运算是一种高效的运算方式,在力扣中经常会用到。例如,左移运算符 << 可以用来计算 2 的幂次方,右移运算符 >> 可以用来除以 2 等等。 5. 使用递归:递归是一种常见的算法思想,在力扣中也经常会用到。例如,二叉树的遍历、链表的反转等等。 6. 使用 STL 中的 priority_queue:priority_queue 是 STL 中的一个容器,可以用来实现堆。在力扣中,使用 priority_queue 可以方便地实现一些需要维护大值或小值的算法。 7. 使用 STL 中的 unordered_map:unordered_map 是 STL 中的一个容器,可以用来实现哈希表。在力扣中,使用 unordered_map 可以方便地实现一些需要快速查找和插入的算法。 8. 使用 STL 中的 string:string 是 STL 中的一个容器,可以用来存储字符串。在力扣中,使用 string 可以方便地处理字符串相关的问9. 注意边界条件:在力扣中,边界条件往往是解决问的关键。需要仔细分析目,考虑各种边界情况,避免出现错误。 10. 注意时间复杂度:在力扣中,时间复杂度往往是评判代码优劣的重要指标。需要仔细分析算法的时间复杂度,并尽可能优化代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九天漩女

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值