問題描述
給定 n 個非負整數表示每個寬度爲 1 的柱子的高度圖,計算按此排列的柱子,下雨之後能接多少雨水。
上面是由數組 [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
分析
- 方法一:暴力解法;每個位置垂直求接水量,求出當前位置左右柱子的最高值。時間複雜度O(),空間複雜度O(1)
- 方法二:動態編程;也是每個位置垂直求水量,我們用兩次循環求得每個位置上的左右柱子的最高值。時間複雜度O(n), 空間複雜度O(n)。
- 方法三:單調棧;水平求接水量,利用單調遞增棧,一遍可求得答案。時間複雜度O(n), 空間複雜度O(n)。
- 方法四:雙指針法;每個位置垂直求接水量,利用雙指針解決:是法二動態編程的優化,時間複雜度O(n),空間複雜度,O(1)。
代碼
class Solution:
# 暴力解法
def trap1(self, height):
res = 0
length = len(height)
for i in range(length):
Lhigh = height[i]
Rhigh = height[i]
for j in range(length):
if j < i:
Lhigh = max(Lhigh, height[j])
elif j > i:
Rhigh = max(Rhigh, height[j])
res += min(Lhigh, Rhigh) - height[i]
return res
# 動態編程
def trap2(self, height):
length = len(height)
maxNum = 0
Rhigh = []
Lhigh = [0] * length
for i in range(length):
maxNum = max(maxNum, height[i])
Rhigh.append(maxNum)
maxNum = 0
for i in range(length-1, -1, -1):
maxNum = max(maxNum, height[i])
Lhigh[i] = maxNum
res = 0
for i in range(length):
res += min(Rhigh[i], Lhigh[i]) - height[i]
return res
# 單調棧
def trap3(self, height):
if not height:
return 0
# 單調遞增棧
stack = []
current = 0
length = len(height)
res = 0
while current<length:
while stack and height[stack[-1]] < height[current]:
cur_index = stack.pop()
if stack: # 形成水平低窪處
cur_bound = current - stack[-1] - 1 # 低窪寬度
cur_height = min(height[current], height[stack[-1]]) - height[cur_index] # 低窪高度
res += cur_bound * cur_height
stack.append(current)
current += 1
return res
# 雙指針法 法二 動態編程推廣
def trap(self, height):
if not height:
return 0
maxL = 0
maxR = 0
pleft = 0
pright = len(height) - 1
res = 0
while pleft<pright:
if height[pleft]<height[pright]:
if height[pleft] < maxL:
res += maxL - height[pleft]
else:
maxL = height[pleft]
pleft += 1
else:
if height[pright] < maxR:
res += maxR - height[pright]
else:
maxR = height[pright]
pright -= 1
return res
if __name__ == '__main__':
height = [0,1,0,2,1,0,1,3,2,1,2,1]
test = Solution()
res = test.trap(height)
print(res)