• 机试打卡 -05 接雨水(动态规划&栈)


     


    我的思路:依次计算每一列能接收的雨水量。
     

    关键点:如何计算得到每一列所能接收到的雨水量?

            某一列能够接收到的雨水量,取决于其左右两侧最高的柱子。仅有当左右两侧的柱子均高于该列的高度,该列才可收到雨水,其雨水量为 min( left_height-h , right_height-h) 。

    1. class Solution:
    2. def trap(self, height: List[int]) -> int:
    3. # height数组->对象属性
    4. self.height=height
    5. self.height_len=len(height)
    6. # 哈希表存储上一时刻的left_height与right_height
    7. Hash=dict()
    8. Hash['left_height']=0
    9. Hash['right_height']=max(height)
    10. self.Hash=Hash
    11. # rain_sum:总雨水量
    12. rain_sum=0
    13. # 依次计算每一个柱子所能接水的高度
    14. # i为索引
    15. for i in range(len(height)):
    16. # 传入柱子的索引
    17. rain_sum+=self.rain_calculate(i)
    18. return rain_sum
    19. def rain_calculate(self,index):
    20. # 取自身高度h
    21. h=self.height[index]
    22. # 左侧高度
    23. if index:
    24. left_height=max(self.Hash['left_height'],self.height[index-1])
    25. else:
    26. left_height=0
    27. # 右侧高度
    28. if self.height[index]!=self.Hash['right_height']:
    29. right_height=self.Hash['right_height']
    30. else:
    31. if index==self.height_len-1:
    32. right_height=0
    33. else:
    34. seq_temp=self.height[index+1:self.height_len]
    35. right_height=max(seq_temp)
    36. # 更新哈希表
    37. self.Hash['left_height']=left_height
    38. self.Hash['right_height']=right_height
    39. # 仅有当left_height和right_height均高于h时,该列才可接收到雨水
    40. if left_height>h and right_height>h:
    41. return min(left_height-h,right_height-h)
    42. else:
    43. return 0

    关键点:哈希表存储上一时刻的left_height与right_height

    为什么需要存储上一时刻的left_height与right_height?

            数组从左往右遍历,新柱子的 left_height 直接取 max(前一个柱子的left_height , 前一个柱子的高度),有些类似递归的思想。

            新柱子的 right_height 则分为两种情况,一种是 新柱子的高度不等于前一个柱子的 right_height,这种情况下则令新柱子的 right_height 直接取 前一个柱子的 right_height 即可;另一种情况则是 新柱子的高度等于前一个柱子的 right_height,即说明前一个柱子的 right_height 可能取自该根柱子,则新柱子的 right_height 取后面的柱子的最大值(数组切片) 即可。


    思路2:动态规划

    动态规划 - 复杂度分析

    时间复杂度为:O(n)

    空间复杂度为:O(n)


    思路3:单调栈

    1. class Solution:
    2. def trap(self, height: List[int]) -> int:
    3. ans = 0
    4. # 建立单调递减栈,用列表存储
    5. stack = list()
    6. # 从左向右依次遍历
    7. for i, h in enumerate(height):
    8. # 当栈不为空且h大于栈顶的高度时,进入while循环
    9. while stack and h > height[stack[-1]]:
    10. # 取出栈顶元素,作为低洼
    11. top = stack.pop()
    12. # 若取出栈顶元素后栈为空,则跳出while循环
    13. if not stack:
    14. break
    15. # left为左边界的索引,i为右边界的索引
    16. left = stack[-1]
    17. currWidth = i - left - 1
    18. currHeight = min(height[left], height[i]) - height[top]
    19. ans += currWidth * currHeight
    20. # 循环结束后,将i加入栈中
    21. stack.append(i)
    22. return ans

    关键点:单调递减栈

            考虑到低洼(可接雨水)必须有左右两侧边界,所以用python列表建立单调递减栈。当出现某一根柱子大于栈顶元素的高度时,开始进入内循环。出栈的top为低洼,根据left和right边界索引计算雨水存量,直到下一个栈顶大于等于h,方可跳出内循环。最后一定要将 i 入栈,因为 i 仍可能可以构成某一个低洼的左边界。

  • 相关阅读:
    flutter问题汇总
    基于CNN-RNN模型的验证码图片识别
    【Java第22期】:Thread 类的基本用法
    js调用(前/后)摄像头,截取照片,关闭摄像头
    C函数使用
    【编程题】【Scratch四级】2022.06 绘制多变的正方形
    数据结构和算法——排序算法
    Linux版 MCSM9 面板更新教程
    MongoDB聚合运算符:$setDifference
    DataTable数据导出保存到文件、Excel文件导入到DataTable
  • 原文地址:https://blog.csdn.net/qq_55818063/article/details/130843889