给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:

输入:height = [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 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5] 输出:9
1.按层暴力求解:
按第i行进行遍历,比较height[ i ]与i的大小:
1.若height [ i ] >= i : res += temp,temp = 0
2.若height [ i ]
很可惜,这样做可恶的超出了时间限制。
- def trap(self, height):
- # 解法1 : 按第i行进行遍历,看height[i]与i的大小比较
- # 若height[i] >= i: res += temp temp = 0
- # 若height[i] < i: temp += 1
- res = 0
- max_water_level = 0
- for i in range(len(height)):
- if height[i] > max_water_level:
- max_water_level = height[i]
- for i in range(1,max_water_level + 1):
- temp = 0
- isStart = False
- for j in range(len(height)):
- if height[j] < i and isStart:# 之前没有比i高的柱子就没有水
- temp += 1
- if height[j] >= i:
- res += temp
- temp = 0
- # 之前有比i高的柱子了
- isStart = True
- return res

2.聚焦于求每列的水:
1. 首先求[0 , i-1]中最高的柱子。
2. 其次求[0 , i - 1]和[i + 1 , len - 1]中最高的柱子。
3. 比较当前列高度和左右最高柱子的较低值,若当前列高度大,则没水;若当前列高度小,则水量为 左右最高柱子的较低值 - 当前柱子高度。
这种做法产生了比较有意思的现象:java可以AC,而python差两个用例AC,在处理高并发、多数据量的情况下,java还是有得天独厚的优势!
python:
- def trap(self, height):
- # 解法2 : 聚焦于求每列的水
- # 如何求某列的水:1.求[0,i-1]中最高的柱子 2.求[i+1,len-1]中最高的柱子 3.比较当前列高度和左右高柱子的较低值
- def max_height(nums,start,end):
- max_val = 0
- for index in range(start,end+1):
- if nums[index] > max_val:
- max_val = nums[index]
- return max_val
- res = 0
- lens = len(height)
- for i in range(1,lens-1):
- left_max = max_height(height,0,i-1)
- right_max = max_height(height,i+1,lens - 1)
- lower_max = min(left_max,right_max)
- if lower_max > height[i] :
- res += (lower_max - height[i])
- return res

java:
- public int trap(int[] height) {
- int res = 0, i,j;
- for(i = 1 ; i < height.length - 1 ; i++){
- int left_max = 0;
- int right_max = 0;
- for(j = 0 ; j <= i-1 ; j++){
- if(height[j] > left_max)
- left_max = height[j];
- }
- for(j = i+1 ; j < height.length ; j++){
- if(height[j] > right_max)
- right_max = height[j];
- }
- int lower_max = Math.min(left_max,right_max);
- if (lower_max > height[i]){
- res += (lower_max - height[i]);
- }
- }
- return res;
- }

3.动态规划

另外定义数组:max_left[n]、max_right[n]
1.max_left[i] 代表前[0,i-1]中的最大值,比较max_left[i-1]与height[i-1]即可
2.max_right[i]代表后[i+1,n]中的最大值,比较max_right[i+1]与height[i+1]即可
3.最后在[1,lens-1]中判断height[i]与max_left[i]和max_right[i]的小值哪个大,若height[i]大,则height没有水;若height[i]小,则盛水量即为两值之差。
- def trap(self, height):
- res = 0
- lens = len(height)
- max_left,max_right = [0] * lens,[0] * lens
- for i in range(1,lens):
- max_left[i] = max(max_left[i-1],height[i-1])
- for i in range(lens-2,-1,-1):
- max_right[i] = max(max_right[i+1],height[i+1])
- for i in range(lens-1):
- lower_max = min(max_left[i],max_right[i])
- if lower_max > height[i]:
- res += (lower_max - height[i])
- return res

4.栈(参考括号匹配的问题)
1.当栈为空或者栈顶元素>=当前下标元素时,height数组值在呈现下降的趋势,即当前位于坑的左边,所以这时还不知道这个水坑的深度有多少,所以继续往栈内存。
2.当栈不为空或者栈顶元素<当前下标元素时,height数组值在呈现上升的趋势,即当前位于坑的右边,此时水坑的深度已经知道了,所以可以开始计算水量,每上一个台阶的时候,计算当前的水量即可。
3.水量的计算:首先计算当前水量的长度distance,即当前下标值 - 栈顶存放的下标 - 1;其次计算高度height,即栈顶下标对应的值和当前下标对应值的较小值;最后计算水量的面积的时候要减掉上次计算过水量的高度值,即 s = distance * (height - h),其中 h 在每次计算前都等于前一个出栈的下标对应的值。
- def trap(self, height):
- # 解法5 : 栈
- # helper[]
- current_index,lens = 0,len(height)
- helper = []
- res = 0
- while current_index < lens:
- # 栈不为空且当前指向高度大于栈顶元素高度
- while helper and height[helper[-1]] < height[current_index]:
- x = height[helper[-1]]
- helper.pop()
- if not helper:
- break
- # 计算当前存储的水量
- distance = current_index - helper[-1]- 1
- hit = min(height[current_index],height[helper[-1]])
- res += (distance * (hit -x ))
- helper.append(current_index)
- current_index += 1
- return res
