接雨水
https://leetcode-cn.com/problems/trapping-rain-water/
暴力法
一个格子 i 能接多少水,取决于它左右两边最高的柱子的最小值,减去它自己的高度 height[i]。可以对于每个格子 i 都寻找它左右两边最高柱子,复杂度为 O(n^2)。
动态规划
可以利用动态规划预先记录每个格子左边以及右边的最高长度。
具体地,用两个数组记录,leftMax[i] 表示第 [0..i] 的最高柱子高度(包括了 i 自己),base case 就是 leftMax[0] = height[0]。右边的最高高度同理,算出这两个数组后,计算结果仅需 O(n) 复杂度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | func trap(height []int) int {     n := len(height)     leftMax := make([]int, n)     rightMax := make([]int, n)
      leftMax[0] = height[0]     rightMax[n-1] = height[n-1]
      for i := 1; i < n; i++ {         leftMax[i] = max(height[i], leftMax[i-1])     }     for j := n-2; j >= 0; j-- {         rightMax[j] = max(height[j], rightMax[j+1])     }
      res := 0     for i := 0; i < n; i++ {         res += min(leftMax[i], rightMax[i]) - height[i]             }
      return res }
 
  | 
 
双指针
利用两个指针 left 和 right 从左右两边向中间靠近并计算 height[left] 或 height[right] 能装的雨水,同时更新左侧和右侧的最高值。
由于已经判断了 leftMax < rightMax,因此直接取其中更小者即可,而不用关心另一侧是不是没找到最高的柱子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | func trap(height []int) int {     n := len(height)
      leftMax, rightMax := 0, 0     left, right := 0, n-1     res := 0
      for left < right {         leftMax = max(leftMax, height[left])         rightMax = max(rightMax, height[right])
          if leftMax < rightMax {             res += leftMax - height[left]             left++         } else {             res += rightMax - height[right]             right--         }     }
      return res }
 
  | 
 
盛最多水的容器
https://leetcode-cn.com/problems/container-with-most-water/
类似的道理,利用双指针解决,用 left 和 right 两个指针从两端向中心收缩,一边收缩一边计算 [left, right] 之间的矩形面积,取最大的面积值即是答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
   | func maxArea(height []int) int {     n := len(height)     var leftMax, rightMax int     left, right := 0, n-1
      res := 0     for left < right {         leftMax = max(leftMax, height[left])         rightMax = max(rightMax, height[right])
          var curr int         if leftMax < rightMax {             curr = leftMax * (right - left)             left++         } else {             curr = rightMax * (right - left)             right--         }
          if curr > res {             res = curr         }     }
      return res }
 
  |