【leet-code清晰解题思路💯✅】42. 接雨水

93 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

题目描述

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

解题思路

  • 我们可以把陆地分成三个部分,左半边,中间,右半边。这三者的分界线就是最高点。如果只有一个最高点,就没有中间部分,以最高点为界分成左右两边。如果有多个相同的最高值,第一个最大值左、最后一个最大值右为为左右部分,中间的部分为中间部分。

  • 有了这三部分我们可以分类讨论

    • 对于左半部分,他是逐渐递增的,根据短板效应,从左向右短板不断提高。如果后面出现低于短板的值,我们就可以补上水。这就是一个for循环遍历即可。
    • 对于中间部分,我们知道短板就是最高值,所以直接遍历补充即可。
    • 对于右半部分他与左部分正好相反,利用相同的思路,我们从右向左遍历补水即可。
  • 上面的思路只需要O(n)的时间复杂度。

func trap(height []int) int {
   maxh := 0
   for i := 0; i < len(height); i++ {
      maxh = max(maxh, height[i])
   }
   // 计数左部分
   ans := 0
   l, r := 0, len(height)-1
   tmpm := height[0]
   for ; l < len(height); l++ {
      if height[l] == maxh {
         break
      }
      if height[l] < tmpm {
         ans += tmpm - height[l]
      }
      tmpm = max(tmpm, height[l])
   }
   // 计算右部分
   tmpm = height[len(height)-1]
   for ; r >= l; r-- {
      if height[r] == maxh {
         break
      }
      if height[r] < tmpm {
         ans += tmpm - height[r]
      }
      tmpm = max(tmpm, height[r])
   }
   // 计算中间
   for ; l <= r; l++ {
      if height[l] < maxh {
         ans += maxh - height[l]
      }
   }
   return ans
}

image.png