单调栈总结篇。

单调栈的特点:

1.别看又是for又是while的,复杂度是o(n)

2.解决四种问题  左边比我  大的/小的  第一个元素    以及  右边比我  小的/大的  第一个元素

记住一定是左边或者右边的 第一个  ,第一个,第一个。重要的事情说三遍。

题目:739  496  503,42,84

接下来一个一个搞起。

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]

我们用这一个题目讲下这玩意怎么用

首先这摆明了要求一个数字右边最大的第一个值,ok上单调栈。之前我们先定义点东西:

 int[] res = new int[temperatures.length];         //返回值
 Deque<Integer> queue = new LinkedList<Integer>();//首先得有个栈嘛,我这写的是queue,因为用的deque

然后该遍历了。从前往后还是从后往前?从后面往前面好点,因为我们要求的是右边最大,而且是第一个。从右边遍历回来就可以把数组收了。

queue里面存的是我当前元素的后面,记住这个设定。

int[] res = new int[temperatures.length];
        Deque<Integer> queue = new LinkedList<Integer>();
        for (int i=temperatures.length-1; i>=0 ; i--) { 
             //我发现我while经常写成if,意思是什么呢?就是如果我当前元素的后面还比我小,那就去了吧
             while(!queue.isEmpty()  &&
                temperatures[queue.peek()] <= temperatures[i]){
                 queue.pop();,

比如下面这个图,cur是第一个绿条条,值是2,后面的一个棕色条条是1,还跟着一个更小的棕色条条,

96a92dee434747939b3574118af1da10.jpg

 

那如果我们把棕色条条pop掉,三个绿色的是不是就是单调递增,然后cur的后面那个不就是第一个比它大的了吗(也就是peek元素),如下图
             781b078d32264bfdad50757fa6f81d65.jpg

 接着怎么办?收res。然后别忘记把cur也收入到queue里面
             res[i] = queue.isEmpty()?0:queue.peek()-i;//记得减去i
             queue.push(i);
        }
        return res;

完整代码:

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int[] res = new int[temperatures.length];
        Deque<Integer> queue = new LinkedList<Integer>();
        for (int i=temperatures.length-1; i>=0 ; i--) { 
             //我发现我while经常写成if
             while(!queue.isEmpty()  &&
                temperatures[queue.peek()] <= temperatures[i]){
                 queue.pop();
             }
             res[i] = queue.isEmpty()?0:queue.peek()-i;//记得减去i
             queue.push(i);
        }
        return res;
    }
}

 

 

496.下一个更大的元素

给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。

请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。

nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。

示例 1:

输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
解释:
对于 num1 中的数字 4 ,你无法在第二个数组中找到下一个更大的数字,因此输出 -1 。
对于 num1 中的数字 1 ,第二个数组中数字1右边的下一个较大数字是 3 。
对于 num1 中的数字 2 ,第二个数组中没有下一个更大的数字,因此输出 -1 。

示例 2:
输入: nums1 = [2,4], nums2 = [1,2,3,4].
输出: [3,-1]
解释:
对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。
对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出-1 。

提示:

  • 1 <= nums1.length <= nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 10^4
  • nums1和nums2中所有整数 互不相同
  • nums1 中的所有整数同样出现在 nums2 中

 

 

我们瞅瞅啊,和上一个题目好像差不多的。

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int[] res = new int[nums1.length];
     
     
     for(int j=0;j<nums1.length;j++){
     int indexInNum2 =-1;
     //stack放在里面,防止上一次stack没清理干净。
     Deque<Integer> stack = new LinkedList<Integer>();
     for(int i=nums2.length-1;i>=0;i--)   {
         
         if(nums1[j]==nums2[i]){
             indexInNum2=i;
             break;
         }
     }
     System.out.println(nums2.length-1+" "+indexInNum2);
     for(int i=nums2.length-1;i>=indexInNum2;i--){
        
         int realIndex=i;
         while(!stack.isEmpty()
         && stack.peek()<=nums2[realIndex]){
             stack.pop();
         }
         
         res[j] = stack.isEmpty() ?-1:stack.peek();
         stack.push(nums2[realIndex]);
         
     }}
     return res;
    }
}

 

 

 

 

503

和上一道题差不多,但是它变成环了。

变成环有一种方法就是把一个一模一样的数组给它从后面接上

那么遍历的时候就要取模

首先我想想哦

单个的时候倒着遍历好像是从

i=nums.length-1开始的

那么i=(nums.length-1)x2就遍历对吗

对你个头!为什么要减一是因为从0开始

所以应该是2xnums.length-1

然后具体到某一个取个模就可以了

然后要注意,push进去的不是下标了哈!

这次是值

代码:be7a3e80426c4620922327b5fb8dc347.jpg

我们先看84题,直方图里面最大那个矩形

206e2eddf830473b845870fddce8dddd.jpg

 这道题我们以每一个矩形的视角来看待

如果我是2,以我的高度能构造的最大好像就我自己

然后我是1,我应该可以一直延伸,如下图:

d43f7174e2db45cc8384c30274ef5005.jpg

 那么对于一个矩形条来说,它能构造的最大矩形,是由它左边右边各自的[第一个]小于他的值

决定的。

比如上面的5,受限于它左边第一个小过他研也就是1,右边第一个小过它也就是2,所以只能构造5和6两条,最大就是10。

我们上面维护过右边第一个大的数组,那么这次维护两个数组

left和right

left[i]代表在i位置,左边第一个比nums[i]小的值离i的距离。

right[i]代表在i位置,右边第一个比nums[i]小的值离i的距离。

然后注意一下边界,最左边下标是-1,最右边是nums.length

如果最左边没有比nums[i]小的,默认-1处比它小,那么push的距离应该是nums[i]减去-1,也就是nums[i+1]

同理最右边是nums.length-i

上代码

class Solution {
    public int largestRectangleArea(int[] heights) {
    Deque<Integer> stack = new
    LinkedList<Integer>();
    int n = heights.length;
    int[] left = new int[n];
    int[] right = new int[n];
    //求左边第一个比自己小的的距离,求左边那么正着遍历
    for(int i=0;i<n;i++){
       while(!stack.isEmpty() && heights[stack.peek()]>=heights[i]){
           stack.pop();
       }
       left[i] = stack.isEmpty()?
           i +1:i-stack.peek();
       stack.push(i);
    }
    //千万记得clear
    stack.clear();
    //求右边第一个比自己小的距离,求右边反着遍历
    for(int i=n-1;i>=0;i--){
       while(!stack.isEmpty()  && heights[stack.peek()]>=heights[i]){
           stack.pop();
       }
       right[i] = stack.isEmpty()?
            heights.length-i:stack.peek()-i;
       stack.push(i);
    }
    int res = 0;

//每条矩形条构造自己的最大矩形
    for(int i=0;i<n;i++){
        System.out.println(
        left[i]+" "+right[i]+" "+heights[i]
        );
        res=Math.max(((
        left[i]>=1?left[i]-1:0)
        +(right[i]>=1?right[i]-1:0)
       +1 )*heights[i],res);
    }
    return res;
    }
}

 

然后接下来是42题,这题就有点难了

6a9266c2a7b5466faca3eef3b9b08ebb.jpg

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值