算法题——接雨水

59 阅读1分钟

给定 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

题解1:动态规划

牢记柱子能装多少水,取决于它左边的最高柱子和右边的最高柱子。

对于任意位置 i 的柱子:

water=Math.min(leftMax[i],rightMax[i])height[i]water=Math.min(leftMax[i],rightMax[i])-height[i]
  • 如果左边最高比右边最高矮,那么水只能存到左边的高度。
  • 如果右边最高比左边最高矮,那么水只能存到右边的高度。
var trap = function(height) {
  const n=height.length
  if(n===0) return 0
  
  const leftMax=new Array(n).fill(0)
  const rightMax=new Array(n).fill(0)
  for(let i=1;i<n;i++){
    leftMax=Math.max(leftMax[i-1],height[i])
  }
  
  for(let i=n-2;i>=0;i--){
    rightMax=Math.max(rightMax[i+1],height[i])
  }
  
  //开始计算储水量
  let water=0
  for(let i=0;i<n;i++){
    water+=Math.min(leftMax,rightMax)-height[i]
  }
  return water
}

题解2:双指针——“谁矮移谁,算水靠矮边”

思路

  1. 用两个指针 leftright,从两端向中间移动
  2. leftMaxrightMax 记录左右最高柱子
  3. 每次移动高度较小的那一边,因为较小的一边能确定水量
var trap = function(height) {
  let water=0
  let left=0,right=height-1
  let leftMax=0,rightMax=0
  
  while(left<right){
    leftMax=Math.max(leftMax,height[left])
    rightMax=Math.max(rightMax,height[right])
    if(height[left]<height[right]){
      water+=leftMax-height[left]
      left++
    } else {
      water+=rightMax-height[right]
      right--
  }
  return water
}