直方图的水量
题目要求
解题思路
使用面向列的计算比面向行的计算更加容易。我们只需要考虑当前的位置的左右最高模板的高度。
方法一、暴力解法
每个位置能接到多少雨水,很容易想到[木桶效应],即是由两边最短的木板限制的。那么直观思路就是,对于每个位置,向左右找最高的木板,当前位置能放的水量是:左右两边最高木板的最低高度-当前高度。
方法二、动态规划
从暴力法向两边求最高木板,这里其实是有重复计算的。比较直观的优化思路是:先提前遍历一次,求出每个位置左右最高的模板,把结果保存在数组里。就可以避免求解雨水的for
循环中计算高度了。
方法三、双指针
双指针解法是上面的解法的进一步优化,主要作用是为了降低空间复杂度。
使用了两个指针left
和right
分别指向左右两个端点的柱子。
另外用lHeight
和rHeight
分别表示左右两个指针遇到过的最高的柱子,注意上面的动态规划做法是提前计算出来每个位置的最高柱子。
双指针移动的思想是看left和right两个柱子那个更矮,因为蓄水时的瓶颈时更矮的柱子,而更高的柱子其实是不用考虑的。所以每次把更爱的柱子向中间移动。
代码
暴力法
class Solution:
def trap(self, height: List[int]) -> int:
res=0
for i in range(1,len(height)-1,1):
lHeight=max(height[:i])
rHeight=max(height[i+1:])
h = min(lHeight,rHeight) - height[i]
if h>0:
res +=h
return res
动态规划
N=len(height)
if N<2:return 0
lHeight=[0]*N
lHeight[0] = height[0]
rHeight=[0]*N
rHeight[N - 1] = height[N - 1]
for i in range(1,N):
lHeight[i] = max( lHeight[i-1], height[i])
for i in range(N-2,-1,-1):
rHeight[i]=max(rHeight[i+1], height[i])
res=0
for i in range(N):
h = min(lHeight[i],rHeight[i])-height[i]
if h >0:
res +=h
return res
双指针
class Solution(object):
def trap(self, height):
N = len(height)
if N < 2: return 0
left, right = 0, N - 1
lHeight = rHeight = 0
res = 0
while left < right:
if height[left] < height[right]:
if height[left] < lHeight:
res += lHeight - height[left]
else:
lHeight = height[left]
left += 1
else:
if height[right] < rHeight:
res += rHeight - height[right]
else:
rHeight = height[right]
right -= 1
return res
复杂度分析
暴力法 | 动态规划 | 双指针 | |
---|---|---|---|
时间复杂度 | O ( N 2 ) O(N^2) O(N2) | O ( N ) O(N) O(N) | O ( N ) O(N) O(N) |
空间复杂度 | O ( 1 ) O(1) O(1) | O ( N ) O(N) O(N) | O ( 1 ) O(1) O(1) |