leetcode 刷题 log day 59

  • 42. 接雨水
    思路

    • 双指针解法:只是单纯的、直接的、麻烦的、客观的、所有的找到了每个元素左边的最高点和右边的最高点,而当前元素能装的雨水又取决于两边最高点的最低点(最低点 - 当前元素的值),遍历所有元素计算每个元素能装多少雨水,加起来即可;
    • 动态规划:双指针解法是在每次遍历到元素的时候又遍历一遍找左边届和右边界,我们可以提前存储每个元素的左边界和右边界,用的时候取就可以~
    • 单调栈:
      1. 当前遍历的元素高度 < 栈顶元素的高度:元素入栈;
      2. 当前遍历的元素高度 = 栈顶元素的高度:弹出上一个,当前元素入栈;
      3. 当前遍历的元素高度 > 栈顶元素的高度:取出栈顶元素(mid,装雨水的底部),然后比较现在的栈顶元素高度(left)和当前元素的高度选取最小值再减去 mid 高度就是装雨水的高度,用当前元素的下标减去 left 再减一就是装雨水的宽度,面积为两者乘积。
    // 双指针解法
    var trap = function(height) {
        let sum = 0;
        for (let i = 0; i < height.length; i++) {
            if (i === 0 || i === height.length - 1) continue;
            let lHeight = height[i], // 左边界
                rHeight = height[i];
            
            for(let l = i - 1; l >= 0; l--) {
                if (height[l] >lHeight) lHeight = height[l];
            }
    
            for(let r = i + 1; r < height.length; r++) {
                if (height[r] > rHeight) rHeight = height[r];
            }
            
            let h = Math.min(rHeight, lHeight) - height[i];
            if (h > 0) sum += h;
        }
        return sum;
    };
    
    // 动态规划:先记录每个元素的左边最大值和右边最大值,然后再遍历算出每个元素可以装的雨水,比双指针每次循环时都要遍历找一遍最大值要好
    var trap = function(height) {
      let sum = 0,
          rHeight = new Array(height.length).fill(0),
          lHeight = new Array(height.length).fill(0);
    
      // 记录每个元素的左边的最大高度
      lHeight[0] = height[0];
      for(let i = 1; i < height.length; i++) {
        lHeight[i] = Math.max(height[i], lHeight[i - 1]);
      }
    
      // 记录每个元素右边的最大高度
      rHeight[height.length - 1] = height[height.length - 1];
      for (let i = height.length - 2; i >= 0; i--) {
        rHeight[i] = Math.max(height[i], rHeight[i + 1]);
      }
      
      for(let i = 0; i < height.length; i++) {
        let h = Math.min(rHeight[i], lHeight[i]) - height[i];
        if (h > 0) sum += h;
      }
    
      return sum;
    }
    // 单调栈
    var trap = function(height) {
      if (height.length <= 2) return 0;
      let stack = [],
          area = 0;
      stack[0] = 0;  // 初始化为第一个元素下标
      for (let i = 0; i < height.length; i++) {
        if (height[i] < height[stack[stack.length - 1]]) {
          stack.push(i);
        }else if(height[i] === height[stack[stack.length - 1]]) {
          stack.pop();
          stack.push(i);
        } else {
          while(stack.length && height[i] > height[stack[stack.length - 1]]) {
            let mid = stack.pop();
            if (stack.length !== 0) {
              const left = stack[stack.length - 1];
              const h = Math.min(height[i], height[left]) - height[mid];
              const w = i - left - 1;
              if (h * w > 0) area += h * w;
            }
          }
          stack.push(i);
        }
      }
    
      return area;
    }
    
    
  • 503. 下一个更大元素II
    思路】这道题比之前的题多了一个环形的条件,我们只要想办法遍历两次即可,可以把 nums 数组拼成由两个 nums 组成的新数组,但这样破坏了 nums 的结构,不太好,我们可以用取余的方法来做 i % nums.length,这样就相当于遍历了两遍~

    var nextGreaterElements = function(nums) {
        let res = new Array(nums.length).fill(-1),
            stack = [];
    
        for (let i = 0; i < nums.length * 2; i++) {  // 取余可以使数组循环两遍
            while(stack.length && nums[i % nums.length] > nums[stack[stack.length - 1]]) {
                const top = stack.pop();
                res[top] = nums[i % nums.length];
            }
            stack.push(i % nums.length);
        }
        return res;
    };
    

https://www.programmercarl.com/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值