给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。(数组以外的区域高度视为0)
数据范围:数组长度
,数组中每个值满足
,保证返回结果满足
要求:时间复杂度
[3,1,2,5,2,4]
5
数组 [3,1,2,5,2,4] 表示柱子高度图,在这种情况下,可以接 5个单位的雨水,蓝色的为雨水 ,如题面图。
[4,5,1,3,2]
2
class Solution: def maxWater(self , arr ): water=0 max_arr_l=[arr[0]]*len(arr)#记录位置i处左侧的最大值 max_arr_r=[arr[-1]]*len(arr)#记录位置i处右侧的最大值 for i in range(1,len(arr)-1): max_arr_l[i]=arr[i-1] if arr[i-1]>max_arr_l[i-1] else max_arr_l[i-1] for i in reversed(range(1,len(arr)-1)): max_arr_r[i]=arr[i+1] if arr[i+1]>max_arr_r[i+1] else max_arr_r[i+1] for i in range(1,len(arr)-1): max_=min(max_arr_l[i],max_arr_r[i]) if max_-arr[i]>0: water+=max_-arr[i] return water
class Solution: def maxWater(self , arr ): # write code here le = len(arr) l = list([0] * le) r = list([0] * le) l[0] = arr[0] r[le - 1] = arr[le - 1] for i in range(1, le): l[i] = max(l[i - 1], arr[i]) r[le - i - 1] = max(r[le - i], arr[le - i - 1]) res = 0 for i in range(1, le - 1): if min(l[i], r[i]) - arr[i] > 0: res += min(l[i], r[i]) - arr[i] return res
我们先明确几个变量的意思:
left_max:左边的最大值,它是从左往右遍历找到的 right_max:右边的最大值,它是从右往左遍历找到的 left:从左往右处理的当前下标 right:从右往左处理的当前下标
定理一:在某个位置i处,它能存的水,取决于它左右两边的最大值中较小的一个。
定理二:当我们从左往右处理到left下标时,左边的最大值left_max对它而言是可信的,但right_max对它而言是不可信的。(见下图,由于中间状况未知,对于left下标而言,right_max未必就是它右边最大的值)
定理三:当我们从右往左处理到right下标时,右边的最大值right_max对它而言是可信的,但left_max对它而言是不可信的。
class Solution: def maxWater(self, arr ): left, right, res, left_max, right_max = 0, len(arr) - 1, 0, 0, 0 while left < right: if arr[left] < arr[right]: if arr[left] > left_max: left_max = arr[left] else: res += left_max - arr[left] left += 1 else: if arr[right] > right_max: right_max = arr[right] else: res += right_max - arr[right] right -= 1 return res