題目
給定 n 個非負整數表示每個寬度爲 1 的柱子的高度圖,計算按此排列的柱子,下雨之後能接多少雨水。
上面是由數組 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度圖,在這種情況下,可以接 6 個單位的雨水(藍色部分表示雨水
思路
- 暴力法
每個位置i能裝的雨點數目,是由0-i1 這一段的最大值和i+1-n-1這一段的最大值,這兩邊的最大值中的較小值- height[i]得到的。因此遍歷到一個位置,就用兩個for分別尋找左右兩邊的最大值。
-
化簡的暴力法
我們還可以先遍歷一遍數組,統計每個每個位置i之前的最大值是多少,存到一個數組中。就是事先把每個位置左邊和右邊的最大值存下來。 -
VN法
這個方法比較巧妙
用兩個變量S1,S2,分別統計: 1. 從左至右 ,每個位置到開頭位置的最大值,然後加上變量上去。2. 從右到左,每個位置到結尾位置的最大值,加到變量上去。
然後 S1+S2 = 總面積 + 重疊面積
重疊面積 = 雨水面積 + sum(height) -
單調棧
之前也有一道單調棧的題目, 739.每日溫度.
什麼是單調棧。就是棧內的數據,從棧底到棧頂都是單調的。
這道題需要構建一個遞減的單調棧。因爲假設第i個位置的height大於棧頂,說明棧頂對應的位置是可以接到雨水的,這時候就開始計算一下前一個位置能接多少水。如果棧頂元素是k,且棧頂下面的位置也是k,那這些位置都一起算雨水。
面積爲:( i- j-1) * min(height[i], stack[j]) - k)
cur_top是i的前一個位置。j是不等於k且離k最近的位置。
class Solution:
def trap(self, height: List[int]) -> int:
stack = [] # val, index
ans = 0
for i in range(len(height)):
while stack and stack[-1][0] < height[i]:
cur = stack.pop()
while stack and stack[-1][0] == cur[0]:
stack.pop()
if stack:
ans += (min(stack[-1][0], height[i]) - cur[0]) * (i - stack[-1][1] -1)
stack.append([height[i], i])
return ans