用javascript分类刷leetcode13.单调栈(图文视频讲解)

本文通过JavaScript详细解析LeetCode中利用单调栈解决42.接雨水、85.最大矩形等硬题的方法,包括动态规划、单调栈和双指针策略,帮助你理解并掌握这些高效算法。
摘要由CSDN通过智能技术生成
42. 接雨水 (hard)

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

示例 1:

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

输入:height = [4,2,0,3,2,5]
输出:9

提示:

n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105

  • 思路:首先考虑暴力做法,找找思路,暴力做法可以遍历数组,在每个位置分别往两边寻找左柱子中的最大高度和右柱子中的最大高度,找到之后,用左右最大高度的较小者减去当前柱子的高度,就是当前位置能接的水量。该方法要循环整个数组,并且每个位置要遍历数组寻找左右柱子高度的最大值,嵌套了一层循环,所以复杂度是O(n^2)

    我们怎样加速嵌套的这层循环呢,其实可以预先计算从左往右和从右往左的最大高度数组,在循环数组的时候,可以直接拿到该位置左右两边的最大高度,当前位置的接水量就是左右两边高度的较小者减去当前位置柱子的高度

  • 复杂度:时间复杂度O(n),寻找左右的最大高度,循环计算每个位置的接水量,总共3个循环,但他们不是嵌套关系。空间复杂度是O(n),n是heights数组,用到了leftMaxrightMax数组,即存放左右两边最大高度的数组。

方法1.动态规划

动画过大,点击查看

js:

var trap = function(height) {
   
    const n = height.length;
    if (n == 0) {
   //极端情况
        return 0;
    }

    const leftMax = new Array(n).fill(0);//初始化从左往右看的最大值数组
    leftMax[0] = height[0];
    for (let i = 1; i < n; ++i) {
   
        leftMax[i] = Math.max(leftMax[i - 1], height[i]);
    }

    const rightMax = new Array(n).fill(0);//初始化从右往左看的最大值数组
    rightMax[n - 1] = height[n - 1];
    for (let i = n - 2; i >= 0; --i) {
   
        rightMax[i] = Math.max(rightMax[i + 1], height[i]);
    }

    let ans = 0;
      //循环数组,每个位置能接的雨水量就是这个位置左右最大值的较小者减去当前的高度
    for (let i = 0; i < n; ++i) {
   
        ans += Math.min(leftMax[i], rightMax[i]) - height[i];
    }
    return ans;
};
方法2:单调栈

动画过大,点击查看

  • 思路:遍历heights数组,将其中的元素加入单调递减栈,如果当前柱子的高度大于栈顶柱子的高度, 不断出栈,相当于找到左边比当前柱子矮的位置,然后每次出栈之后都要累加一下面积。
  • 复杂度:时间复杂度O(n),n是heights的长度,数组中的每个元素最多入栈出栈一次。空间复杂度O(n),栈的空间,最多不会超过heights的长度

js:

var trap = function(height) {
   
    let ans = 0;
    const stack = [];//单调递减栈。存放的是下标哦
    const n = height.length;
    for (let i = 0; i < n; ++i) {
   //循环heights
          //当前柱子的高度大于栈顶柱子的 不断出栈
        while (stack.length && height[i] > height[stack[stack.length - 1]]) {
   
            const top = stack.pop();
            if (!stack.length) {
   //栈为空时 跳出循环
                break;
            }
            const left = stack[stack.length - 1];//拿到当前位置左边比当前柱子矮的位置
            const currWidth = i - left - 1;//计算宽度
            const currHeight = Math.min(height[left], height[i]) - height[top];//计算高度
            ans += currWidth * currHeight;//计算当面积
        }
        stack.push(i);//加入栈
    }
    return ans;
};
方法3.双指针

动画过大,点击查看

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

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值