代码随想录算法训练营第五十九天 |503. 下一个更大元素 II、42. 接雨水

503. 下一个更大元素 II

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

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

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

这道题和739. 每日温度类似,但是这道题可以循环去比较,所以涉及到2个nums数组,所以我们可以循环[0,2*nums.length)每次的索引下标可以是i%nums.length 就会两次遍历nums数组。

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

42. 接雨水

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ahWRZiGA-1680681005247)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3781b66b-9b9e-4df2-9d89-5fe5efaf3e0c/Untitled.png)]

输入: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 个单位的雨水(蓝色部分表示雨水)。

思路一:双指针(按照列来计算)

  1. 设置i的左右指针
  2. 求左边的最大[0,i-1],求右边的最大[i+1,size-1]
  3. 最终雨水的区域是Math.min(lHeight,rHeight)-height[i]
  4. 将每一个i出的雨水区域相加
class Solution {
    public int trap(int[] height) {
        int sum=0;
        for(int i=0;i<height.length;i++){
            if(i==0||i==height.length-1){
                continue;
            }
            int lHeight=height[i];
            int rHeight=height[i];
            for(int j=i+1;j<height.length;j++){
                if(height[j]>rHeight){
                    rHeight=height[j];
                }
            }
            for(int j=i-1;j>=0;j--){
                if(height[j]>lHeight){
                    lHeight=height[j];
                }
            }
            int h=Math.min(lHeight,rHeight)-height[i];
            if(h>0){
                sum+=h;
            }
        }
        return sum;

    }
}

以上代码的简洁版

class Solution {
    public int trap(int[] height) {
        int left = 0, right = height.length - 1;
        int maxL = height[left], maxR = height[right];
        int res = 0;
        while (left < right) {
            maxL = Math.max(maxL, height[left]);
            maxR = Math.max(maxR, height[right]);
            res += maxR > maxL ? maxL - height[left++] : maxR - height[right--];
        }
        return res;
    }
}

思路二:单调栈(根据行来计算)

主要需要考虑三种情况:

  • 情况一:当前遍历的元素(柱子)高度小于栈顶元素的高度 height[i] < height[st.top()]

    将下标index添加到stack中

  • 情况二:当前遍历的元素(柱子)高度等于栈顶元素的高度 height[i] == height[st.top()]

    弹出stack栈顶元素,并将index添加到stack中

  • 情况三:当前遍历的元素(柱子)高度大于栈顶元素的高度 height[i] > height[st.top()]

    取stack弹出的元素为mid,stack剩余的栈顶元素为left,分别求高度和宽度

    h = Math.min(height[left], height[index]) - height[mid];

    w = index - left - 1;

    所以最终雨水范围为h*w

class Solution {
    public int trap(int[] height) {
        int size = height.length;
        if (size <= 2) return 0;
        Stack<Integer> stack = new Stack<Integer>();
        stack.push(0);

        int sum = 0;
        for (int index = 1; index < size; index++){
            int stackTop = stack.peek();
            if (height[index] < height[stackTop]){
                stack.push(index);
            }else if (height[index] == height[stackTop]){
                stack.pop();
                stack.push(index);
            }else{
                //pop up all lower value
                int heightAtIdx = height[index];
                while (!stack.isEmpty() && (heightAtIdx > height[stackTop])){
                    int mid = stack.pop();
                    if (!stack.isEmpty()){
                        int left = stack.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;
                        stackTop = stack.peek();
                    }
                }
                stack.push(index);
            }
        }
        return sum;
    }
}

最后做下来感觉还是双指针更简洁一些

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值