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