0
点赞
收藏
分享

微信扫一扫

乐维更改IP地址

蒸熟的土豆 03-29 17:30 阅读 1
算法

503.下一个更大元素II

本题和每日温度思路基本一致,多出一步对于循环数组的处理。遇到循环数组,第一个想法就是取数组长度的模,即i%len

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

42. 接雨水

本题需要计算能接到多少雨水,也就是计算合理的柱子数目及其容量。合理的柱子需要满足下面的条件:

  • 同时拥有左右两侧
  • 柱子能接雨水的高度取决于矮柱子的高度

那么问题的关键在于,如何判断柱子的左右边界?如何计算容量?

首先更推荐按照列来计算容量,这样子宽度一定为1,把每一列满足条件的高度计算出来即可。

对于确定左右边界,需要分别从左和从右找到最高的列。

第一个柱子和最后一个柱子无法盛雨水

对于列1:

左边没有比当前高的柱子,所以无法盛雨水

对于列2:

  • 左边最高的柱子为列1,高度为1
  • 右边最高的柱子为列7,高度为3
  • 列2高度为0
  • 所以列2能容纳的雨水容量为:min(列1高度,列7高度)-列2高度=1-0=1

对于列3:

左边没有比它更高的柱子,所以无法盛雨水

对于列4:

  • 左边最高的柱子为列3,高度为2
  • 右边最高的柱子为列7,高度为3
  • 列4高度为1
  • 所以列4能容纳雨水容量为:min(列3高度,列7高度)-列4高度=2-1=1

以此类推。但是这个思路需要消耗O(n^2)的时间复杂度,测试用例不通过

class Solution {
    public int trap(int[] height) {
        if(height==null) return 0;
        int sum=0;
        for(int i=1;i<height.length-1;i++){
            int lH=height[i];
            int rH=height[i];
            for(int r=i+1;r<height.length;r++){ //找右边最大的边
                rH=height[r]>rH?height[r]:rH;
            }
            for(int l=i-1;l>=0;i--){// 找左边最大的边
                lH=height[l]>lH?height[l]:lH; 
            }
            int h=Math.min(lH,rH)-height[i];
            if(h>0) sum+=h;
        }
        return sum;
    }
}

可以看到本题本质依然是寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,接雨水这道题目,我们正需要寻找一个元素,右边最大元素以及左边最大元素,来计算雨水面积,所以还是可以考虑用到单调栈。

将本题看作求每根柱子可以容纳雨水的体积,高度为下图所示:

宽度如下图:

先将a,b,c压入栈中,此时遇到了一个比栈顶e的高度更大的c,

则e柱能容纳的水高度为min(b,c)-e,宽度为c的下标-b的下标;

b柱能容纳的雨水高度为min(a,c)-b,宽度为 c的下标-a的下标;

最后能容纳的雨水容量为高*宽

class Solution {
    public int trap(int[] height) {
        if(height==null) return 0;
        int sum=0;
        Stack<Integer> stack= new Stack<>();
        int len=height.length;
        stack.push(0);
        for(int i=1;i<len;i++){
            while(!stack.isEmpty() && height[stack.peek()]<height[i]){
                int top=height[stack.peek()];  //先记录栈顶元素的高度
                stack.pop(); //将栈顶元素弹出
                if(!stack.isEmpty()){//说明有左边
                    int h=Math.min(height[stack.peek()], height[i])-top;  //计算高度
                    int w=i-stack.peek()-1;
                    sum+=h*w;
                }
            }
            stack.push(i);
        }
        return sum;
    }
}

84.柱状图中最大的矩形

本题看起来和接雨水很类似,都是求面积,但是接雨水是找每个柱子左右两边第一个大于该柱子高度的柱子,分别求宽和高然后相乘,而本题是找左右两侧最近的高度小于当前高度的柱子,所以本题应该是从栈顶到栈尾单调递减栈

class Solution {
    public int largestRectangleArea(int[] heights) {
        int max=0;
        Stack<Integer> stack = new Stack<>();
        int len=heights.length;
        int[] newHeight = new int[len+ 2]; //定义一个新数组,加入头和尾
        System.arraycopy(heights, 0, newHeight, 1, len); 
        for(int i=0;i<newHeight.length;i++){
             while (!stack.isEmpty() && newHeight[i] < newHeight[stack.peek()]) {//需要弹
                int h=newHeight[stack.peek()];
                stack.pop();
                int w=i-stack.peek()-1;
                max=max>h*w?max:h*w;

            }
            stack.push(i);
        }
        return max;
    }
}

举报

相关推荐

0 条评论