Day51 算法记录| 动态规划 18(单调栈)


单调栈:找最近的比他大的值
最近大的值:需要一个单调递减的栈(大于栈顶元素就弹出)
最近最小值:单调递减栈

方向: 右边,从后往前遍历 左边:从头遍历

739. 每日温度

单调栈:找最近的比他大的值
我最开始也是两层for循环,严重超时
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为O(n)。

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
     int n = temperatures.length;
     int[] res = new int[n];
     Deque<Integer> stack = new LinkedList<>();

     for(int i=0;i<n;i++){
         while(!stack.isEmpty()&&temperatures[i]>temperatures[stack.peek()]){
             int index = stack.pop();
             res[index] = i - index;
         }
         stack.push(i);
     }
     return res;
    }
}

496.下一个更大元素 I

我自己的思路:
直接用上面的方法,求出原有的nums2 [ ] 对应的res2[ ],里面存放的是下一个大的值
然后两层for循环遍历,求出nums1[ ]对应的res1[ ]

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        int n = nums1.length;
      int[] res1 = new int[n];
      int[] res2 = next(nums2);
      for(int i=0;i<n;i++){
          for(int j=0;j<nums2.length;j++){
              if(nums1[i] == nums2[j]){
                  res1[i] = res2[j];
              }
          }
      }
      return res1;
    }

    private int[] next(int[] nums2){
     int n = nums2.length;
     int[] res = new int[n];
     Arrays.fill(res,-1);
     Deque<Integer> stack = new LinkedList<>();

     for(int i=0;i<n;i++){
         while(!stack.isEmpty()&&nums2[i]>nums2[stack.peek()]){
             int index = stack.pop();
             res[index] =nums2[i];
         }
         stack.push(i);
     }
     return res;
    }
    
}

单调栈和哈希表

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
    Deque<Integer> stack = new LinkedList<>();
    HashMap<Integer,Integer> map = new HashMap<>();// 键放nums2的元素,值放比它大的最近的元素

    for(int num :nums2){
        while(!stack.isEmpty()&& num>stack.peek()){
            map.put(stack.pop(), num);
        }
        stack.push (num);
    }

    int[] res = new int[nums1.length];
    for(int i=0;i<nums1.length;i++){
       res[i] = map.getOrDefault(nums1[i],-1);
       
    }
  return res;
    }
}

503. 下一个更大元素 II

和739一模一样,只是多了扩大数组这一步

在这里插入图片描述

class Solution {
    public int[] nextGreaterElements(int[] nums) {
   Deque<Integer> stack = new LinkedList<>();
   int n = nums.length;

   int[] newArr = Arrays.copyOf(nums, 2*n); //newArr = [nums,nums] 扩展成两倍
    System.arraycopy(nums, 0, newArr, n, n);

   int[] res = new int[2*n]; //右边最近的大值
    Arrays.fill(res,-1);

   for(int i=0;i<2*n;i++){
       while(!stack.isEmpty()&&newArr[stack.peek()]<newArr[i]){
           res[stack.pop()] = newArr[i];
       }
       stack.push(i);
   }
   
   int[] newRes =  Arrays.copyOf(res, n); // 只需要前n个数据
 
  return newRes;
    }
}

不需要扩展了,想要遍历前面的数据就用:i%n来表示循环,i<2n,循环两次

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

42. 接雨水

在这里插入图片描述

两种方法都讲解的超级好呀!!!

方法一:
当前位置能接到的水 = MIN(前面的最大高度, 后面的最大高度)- 当前的高度

class Solution {
    public int trap(int[] height) {

        int n = height.length;
        int[] pre = new int[n]; //
        int[] next = new int[n];
        
       pre[0] = height[0];
        for(int i=1;i<n;i++){
            pre[i] = Math.max(pre[i-1],height[i]);
        }

        next[n-1] = height[n-1];
        for(int j=n-2;j>=0;j--){
            next[j]=Math.max(next[j+1],height[j]);
        }
       
       int ans =0;
       for(int i=0;i<n;i++){
          ans +=Math.min(pre[i],next[i]) - height[i];
       }
        
   return ans;
    }
}

思路二:
如果前缀最大值 < 后缀最大值, 左边 l e f t left left木桶的容量就是 前缀最大值 - h e i g h t [ i ] height[i] height[i]
如果前缀最大值 > 后缀最大值, 右边 r i g h t right right木桶的容量就是 后缀最大值 - h e i g h t [ i ] height[i] height[i]

class Solution {
    public int trap(int[] height) {
    int left =0;
    int right = height.length-1;
    int ans = 0;
    int pre = 0;
    int suf =0;

    while(left<=right){
       pre = Math.max(height[left],pre);
       suf = Math.max(height[right],suf);

       if(pre<suf){
           ans += pre - height[left];
           left++;
       }else{
           ans += suf-height[right];
           right--;
       }
    
    }
       
   return ans;
    }
}

方法三:单调栈

找左右比自己大的元素, 当前位置的面积= (矮柱子-当前高度)*两柱子之间的宽度

class Solution {
    public int trap(int[] height) {
    Deque<Integer> stack = new LinkedList<>();
    int ans =0;

    for(int i=0;i<height.length;i++){
        while(!stack.isEmpty()&& height[i] > height[stack.peek()]){
            int cur = height[stack.pop()];
            if(!stack.isEmpty()){
            int h = Math.min(height[stack.peek()],height[i]);
            ans += (h-cur)*(i-stack.peek()-1); //是两柱子之间的高度,所以-1
            }
        }
        stack.push(i);
    }
   return ans;
    }
}

84. 柱状图中最大的矩形

在这里插入图片描述

和上一题思路类似,找到左右两边比自己小的元素
比自己小的:所以需要单调递增的栈
每个点对应的最大面积 m a x max max =( 右边最近小 - 左边最近小 -1) * 当前高度

class Solution {
    public int largestRectangleArea(int[] heights) {
        int n = heights.length;
     int[] newH = new int[n+2];
     System.arraycopy(heights,0,newH,1,n);
     int ans =0;

     Deque<Integer> stack = new LinkedList<>();
     for(int i=0;i<n+2;i++){
         
         while(!stack.isEmpty() && newH[i]<newH[stack.peek()]){
             int cur = newH[stack.pop()];
             if(!stack.isEmpty()){
                 int l = stack.peek(); //左边比它低的
                 ans = Math.max(ans,cur*(i-l-1));
             }
         }
         stack.push(i);
     }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值