代码随想录算法训练营第59天 | 503、42

文章提供了两道编程题的解决方案,第一题是关于在循环数组中寻找每个元素的下一个更大元素,利用单调栈的方法解决;第二题是计算给定柱子高度图所能接住的雨水量,可采用双指针或单调栈策略。两题均强调对数据结构和算法的理解与应用。

503. 下一个更大的元素Ⅱ

题目描述

给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。
数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。
示例1:
输入:nums=[1,2,1]nums = [1,2,1]nums=[1,2,1]
输出:[2,−1,2][2,-1,2][2,1,2]
示例1:
输入:nums=[1,2,3,4,3]nums = [1,2,3,4,3]nums=[1,2,3,4,3]
输出:[2,3,4,−1,4][2,3,4,-1,4][2,3,4,1,4]

思路

在496题的基础上变成了循环数组,会想到,可以用两个nums拼接模拟。其他的部分和496完全相同。

解法

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

总结

主要还是看单调栈的代码熟不熟悉,多多看,多多练。

42. 接雨水

题目描述

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例1:
输入:height=[0,1,0,2,1,0,1,3,2,1,2,1]height = [0,1,0,2,1,0,1,3,2,1,2,1]height=[0,1,0,2,1,0,1,3,2,1,2,1]
输出:666
示例2:
输入:height=[4,2,0,3,2,5]height = [4,2,0,3,2,5]height=[4,2,0,3,2,5]
输出:999

思路

本题可以有两种思路,一种是双指针,一种是单调栈。但我一种都没有,直接上答案了。
双指针:
记录左边柱子的最高高度和右边柱子的最高高度,就可以i计算当前位置的雨水面积,即,当前雨水面积=min(左边柱子的最高高度,右边柱子的最高高度)-当前柱子高度
为了能够得到两侧的最高高度,需要使用双指针来遍历,讲每个位置的左边最高高度记录在一个数组中,右边最高高度记录在另一个数组中,以避免重复计算。
单调栈:
其实会比双指针更好看出来一些,看到题的时候会有点单调栈的感觉。
本题在发现添加的柱子高度大于栈顶元素时,就出现了凹槽,也就可以加水了。故而需要单调栈内元素从小到大弹出。在遇到高度相同的柱子时,需要使用最右边的柱子来计算宽度。

解法1

class Solution {
    public int trap(int[] height) {
        int length = height.length;
        if(length <= 2){
            return 0;
        }
        int[] maxLeft = new int[length];
        int[] maxRight = new int[length];
        maxLeft[0] = height[0];
        for(int i = 1;i<length;i++){
            maxLeft[i] = Math.max(height[i],maxLeft[i-1]);
        }
        maxRight[length - 1] = height[length - 1];
        for(int i = length - 2;i>=0;i--){
            maxRight[i] = Math.max(height[i],maxRight[i+1]);
        }
        int sum = 0;
        for(int i = 0;i<length;i++){
            int count = Math.min(maxLeft[i],maxRight[i])-height[i];
            if(count > 0){
                sum += count;
            }
        }
        return sum;
    }
}

解法2

class Solution {
    public int trap(int[] height) {
        int size = height.length;
        if(size <= 2){
            return 0;
        }
        Stack<Integer> stk = new Stack<>();
        stk.push(0);
        int sum = 0;
        for(int index = 1;index < size;index++){
            int stkTop = stk.peek();
            if(height[index] < height[stkTop]){
                stk.push(index);
            }
            else if(height[index] == height[stkTop]){
                stk.pop();
                stk.push(index);
            }
            else{
                int heightAtIndex = height[index];
                while(!stk.isEmpty() && (heightAtIndex > height[stkTop])){
                    int mid = stk.pop();
                    if(!stk.isEmpty()){
                        int left = stk.peek();
                        int h = Math.min(height[left],height[index])-height[mid];
                        int w = index - left -1;
                        int hold = h*w;
                        if(hold > 0){
                            sum += hold;
                        }
                        stkTop = stk.peek();
                    }
                }
                stk.push(index);
            }
        }
        return sum;
    }
}

总结

好好看,好好学。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值