给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
题解 本题可转化为求每根柱子上可接到的水量的和, 而每根柱子上可留住的水量又取决于其左右两侧最高的柱子的高度, 假设一根柱子高度为 1, 其左右两侧最高的柱子高度为 3 和 5, 则这根柱子上方可留住的水量为 3 - 1 = 2.
预处理数组法 若每次迭代均遍历查找左右两侧的最大值将增加时间复杂度. 故可采用预处理数组的方式, 将数组中每个元素左右两侧的最大值保存起来. 本例中使用两个辅助数组, 分别保存每个位置上的左侧最大值和右侧最大值. 如下例所示:
1 2 3 [3 , 2 , 4 , 5 , 4 , 3 , 1 ]  [3 , 3 , 4 , 5 , 5 , 5 , 5 ]  [5 , 5 , 5 , 5 , 4 , 3 , 1 ]  
该种解法的时间复杂度和空间复杂度均为为 O(n)
Java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public  class  TrapRainWater  {    public  static  int  trap (int [] heightArr)  {         if  (heightArr == null  || heightArr.length < 0 )             return  0 ;         int  arrLen  =  heightArr.length;         int [] help1 = new  int [arrLen];         int [] help2 = new  int [arrLen];         int  result  =  0 ;         help1[0 ] = heightArr[0 ];         help2[arrLen - 1 ] = heightArr[arrLen - 1 ];         for  (int  i  =  1 ; i < arrLen; i++) {             help1[i] = Math.max(help1[i - 1 ], heightArr[i]);             help2[arrLen - i - 1 ] = Math.max(help2[arrLen - i], heightArr[arrLen - i - 1 ]);         }         for  (int  i  =  1 ; i < arrLen - 1 ; i++) {             int  tmp  =  Math.min(help1[i - 1 ], help2[i + 1 ]) - heightArr[i];             result += Math.max(tmp, 0 );         }         return  result;     }     public  static  void  main (String[] args)  {         int [] heightArr = {0 , 1 , 0 , 2 , 1 , 0 , 1 , 3 , 2 , 1 , 2 , 1 };         System.out.println(trap(heightArr));     } } 
Python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class  TrapRainWater :    def  trap (self, height_arr ):         if  not  height_arr or  len (height_arr) < 0 :             return  0          arr_len = len (height_arr)         help1 = [0 ] * arr_len         help2 = [0 ] * arr_len         result = 0          help1[0 ] = height_arr[0 ]         help2[arr_len - 1 ] = height_arr[arr_len - 1 ]         for  i in  range (1 , arr_len):             help1[i] = max (help1[i - 1 ], height_arr[i])             help2[arr_len - i - 1 ] = max (help2[arr_len - i], height_arr[arr_len - i - 1 ])         for  i in  range (1 , arr_len - 1 ):             tmp = min (help1[i - 1 ], help2[i + 1 ]) - height_arr[i]             result += max (0 , tmp)         return  result 
Go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 func  trap (heightArr []int ) int  {	if  heightArr == nil  || len (heightArr) < 0  { 		return  0  	} 	arrLen := len (heightArr) 	help1 := make ([]int , arrLen) 	help2 := make ([]int , arrLen) 	result := 0  	help1[0 ] = heightArr[0 ] 	help2[arrLen-1 ] = heightArr[arrLen-1 ] 	for  i := 1 ; i < arrLen; i++ { 		help1[i] = max(help1[i-1 ], heightArr[i]) 		help2[arrLen-i-1 ] = max(help2[arrLen-i], heightArr[arrLen-i-1 ]) 	} 	for  i := 1 ; i < arrLen-1 ; i++ { 		tmp := min(help1[i-1 ], help2[i+1 ]) 		result += max(0 , tmp-heightArr[i]) 	} 	return  result } func  max (a, b int ) int  {	if  a > b { 		return  a 	} 	return  b } func  min (a, b int ) int  {	if  a < b { 		return  a 	} 	return  b } 
双指针法 本方法时间复杂度为 O(N) 空间复杂度为 O(1)
Java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public  class  TrapRainWater  {    public  static  int  trap (int [] heightArr)  {         if  (heightArr == null  || heightArr.length < 3 )             return  0 ;         int  arrLen  =  heightArr.length;         int  leftMax  =  heightArr[0 ];         int  rightMax  =  heightArr[arrLen - 1 ];         int  L  =  1 ;         int  R  =  arrLen - 2 ;         int  result  =  0 ;         while  (L <= R) {             if  (leftMax <= rightMax) {                 result += Math.max(0 , leftMax - heightArr[L]);                 leftMax = Math.max(leftMax, heightArr[L++]);             } else  {                 result += Math.max(0 , rightMax - heightArr[R]);                 rightMax = Math.max(rightMax, heightArr[R--]);             }         }         return  result;     } } 
Python 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class  TrapRainWater :    def  trap (self, height_arr ):         if  not  height_arr or  len (height_arr) < 3 :             return  0          arr_len = len (height_arr)         left_max = height_arr[0 ]         right_max = height_arr[arr_len - 1 ]         l = 1          r = arr_len - 2          result = 0          while  l <= r:             if  left_max <= right_max:                 result += max (0 , left_max - height_arr[l])                 left_max = max (left_max, height_arr[l])                 l += 1              else :                 result += max (0 , right_max - height_arr[r])                 right_max = max (right_max, height_arr[r])                 r -= 1          return  result 
Go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 func  trap (heightArr []int ) int  {	if  heightArr == nil  || len (heightArr) < 3  { 		return  0  	} 	arrLen := len (heightArr) 	leftMax := heightArr[0 ] 	rightMax := heightArr[arrLen-1 ] 	L := 1  	R := arrLen - 2  	result := 0  	for  L <= R { 		if  leftMax <= rightMax { 			result += max(0 , leftMax-heightArr[L]) 			leftMax = max(leftMax, heightArr[L]) 			L++ 		} else  { 			result += max(0 , rightMax-heightArr[R]) 			rightMax = max(rightMax, heightArr[R]) 			R-- 		} 	} 	return  result } func  max (a, b int ) int  {	if  a > b { 		return  a 	} 	return  b }