363. 接雨水
中文English
给出 n 个非负整数,代表一张X轴上每个区域宽度为 1
的海拔图, 计算这个海拔图最多能接住多少(面积)雨水。
样例
样例 1:
输入: [0,1,0]
输出: 0
样例 2:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
挑战
O(n) 时间, O(1) 空间
O(n) 时间, O(n) 空间也可以接受
输入测试数据 (每行一个参数)如何理解测试数据?
class Solution: ''' 大致思路: 1.当前位置可以接雨水的数量 = min(左边最大值,右边最大值) - height(当前高度) 2.得到当前位置左右两边最大值列表。最终得到结果。 ''' def trapRainWater(self, heights): # write your code here #得到左,右最大值列表 heights_l = [0] + heights + [0] left_l,right_l = [],[] left_max,right_max = 0,0 for i in range(1,len(heights_l)-1): left_l.append(max(heights_l[:i+1])) right_l.append(max(heights_l[i:])) #开始计算各个位置可以接雨水的数量 res = 0 for j in range(len(heights)): res += min(left_l[j],right_l[j]) - heights[j] return res #result = Solution().trapRainWater([0,1,0,2,1,0,1,3,2,1,2,1]) #print(result)
注:lintcode未通过,代码时间超过限制,max(heights_l[:i+1],取最大值需优化
优化之后:时间复杂度 O(n), 空间复杂度O(n)
class Solution: """ @param heights: a list of integers @return: a integer """ ''' 大致思路: 1.当前位置可以接雨水的数量 = min(左边最大值,右边最大值) - height(当前高度) 2.得到当前位置左右两边最大值列表。最终得到结果。 ''' def trapRainWater(self, heights): left_l = [] right_l = [] l_max,r_max = -sys.maxsize,-sys.maxsize for i in heights: l_max = max(i,l_max) left_l.append(l_max) for j in reversed(heights): r_max = max(j,r_max) right_l.append(r_max) right_l = right_l[::-1] res = 0 for z in range(len(heights)): res += min(left_l[z],right_l[z]) - heights[z] return res
相向型双向指针算法:时间复杂度O(n), 空间复杂度O(1)
class Solution: """ @param heights: a list of integers @return: a integer """ ''' 大致思路: 1.左指针 left_max < right_max 不管当前位置在哪,只需要给出当前位置左边最大值,和右边假定最大值进行比较,如果left_max < right_max,则看左边是否可以接雨水 left_max = max(left_max,当前位置高度) total += left_max - height 只有当前位置 [左边最大高度 右边假定最大高度] 中间才可以接雨水,left_max 来充当两边高度可以挡住的最小值 2.右指针 同上 ''' def trapRainWater(self, heights): if heights == []: return 0 left_max,right_max = heights[0],heights[-1] total = 0 left,right = 0,len(heights) - 1 #在left < right 的时候成立,不能相等,否则left或者right会多走一步。(除非是left += 1放下面) while left < right: if left_max < right_max:#此时假定right_max 为右边可以挡住雨水的墙 #从第二个位置开始看,第一个位置接不了水 left += 1 left_max = max(left_max,heights[left]) total += left_max - heights[left] #如果左边有挡住的最大值墙,则可以接雨水 else:##此时假定左边left_max 为左边可以挡住的墙 #第二个位置开始看 right -= 1 right_max = max(right_max,heights[right]) total += right_max - heights[right] return total
以当前位置为准,判断左右最大值的墙,计算当前位置可以接的雨水量
class Solution: ''' 大致思路: 1.左指针 left_max < right_max 不管当前位置在哪,只需要给出当前位置左边最大值,和右边假定最大值进行比较,如果left_max < right_max,则看左边是否可以接雨水 left_max = max(left_max,当前位置高度) total += left_max - height 只有当前位置 [左边最大高度 右边假定最大高度] 中间才可以接雨水,left_max 来充当两边高度可以挡住的最小值 2.右指针 同上 ''' def trapRainWater(self, heights): if heights == []: return 0 left_max,right_max = heights[0],heights[-1] total = 0 left,right = 0,len(heights) - 1 #在left <= right 的时候成立,当两者刚好相等,则跳出循环 while left <= right: if left_max < right_max:#此时假定right_max 为右边可以挡住雨水的墙 #以当前的位置为准,判断左边墙,出来在left += 1 left_max = max(left_max,heights[left]) total += left_max - heights[left] #如果左边有挡住的最大值墙,则可以接雨水 left += 1 else:##此时假定左边left_max 为左边可以挡住的墙 right_max = max(right_max,heights[right]) total += right_max - heights[right] right -= 1 return total