leetcode 42.接雨水-动态规划 |刷题打卡

159 阅读2分钟

题目:接雨水

继前一种题解之后,优化解题方式,方法发现新大陆

原题详情见力扣

给定 n 个非负整数表示每个宽度为 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 个单位的雨水(蓝色部分表示雨水)。 

思路分析

在前一种解题思路上进行了优化,相当于做了一次缓存

缓存两种

  • 从左往右的每个位置之前的最大值
  • 从右往左的每个位置之后的最大值

做了缓存,这样就不需要再每次进行多余的遍历,节省了时间。

相当于


height = [0,1,0,2,1,0,1,3,2,1,2,1]

// 从左往右遍历
left = [0,1,1,2,2,2,2,3,3,3,3,3]

// 从右往左遍历
right = [3,3,3,3,3,3,3,3,2,2,2,1]

根据左右高度取出二者之间最小的,然后减去自身的柱子高度就是储水量。

伪代码

rain = min(left[i], right[i]) - height[i]

时间复杂度:O(n)

空间复杂度:O(n)

AC 代码

function trap(height = []) {
  const len = height.length

  // 从左往右遍历初始化数组,并初始化首位置
  let left = new Array(len)
  left[0] = height[0]
  // 从右往左遍历初始化数组,并初始化末位置
  let right = new Array(len)
  right[len - 1] = height[len - 1]
  
  // 结果
  let res = 0

  for (let i = 1; i < len; i++) {
    left[i] = Math.max(height[i], left[i - 1])
  }

  for (let i = len - 2; i >= 0; i--) {
    right[i] = Math.max(height[i], right[i + 1])
  }

  for (let i = 0; i < len; i++) {
    res += Math.min(left[i], right[i]) - height[i]
  }

  return res
}

总结

虽然做缓存时间上有所优化,但空间上变成了 O(n),相较于之前的暴力方法相当于是用空间换取了时间,平衡好两者才是最好的选择。

说实话,没看懂为什么这种方式属于动态规划,等了解了,再过来补上。