面试题 17.21. 直方图的水量

这篇博客介绍了如何解决计算机科学中的直方图水量问题,提供了两种高效的算法实现:动态规划和双指针方法。动态规划方案通过维护左右两侧的最大高度数组来计算每个位置的水量;而双指针方法通过左右两个指针逐步收敛,同时更新水量。两种方法的时间复杂度均为O(n),但空间复杂度不同,动态规划为O(n),双指针为O(1)。博客深入解析了这两种算法的思路和实现细节,有助于提升读者在解决数组和算法问题上的能力。
摘要由CSDN通过智能技术生成

面试题 17.21. 直方图的水量

1.题目

在这里插入图片描述

2.官方的解决方案

动态规划

class Solution:
    def trap(self, height: List[int]) -> int:
        # 使用方法:动态规划

        """
        分析思路:
        对于下标i,水能到达的最大高度为i左右两边的最大高度(包括i本位)的最小值
        解释:左边最大高度为2,i为1,右最大高度为3,2 < 3,所以水能到达的最大高度为2
        i位置上能存储的水量,为水能到达的最大高度-i本位的高度height[i]

        创建两个数组:
        leftMax:表示下标i及其左边的位置中,height的最大值
        rightMax:表示i及其右边的位置中,height 的最大值

        leftMax[i] = max(leftMax[i-1], height[i])   1<=i<=n-1
        rightMax[i] = max(rightMax[i+1], height[i]) 0<=i<n-1
        
        最终的结果:
        i位置能接的水量,等于min(leftMax[i], rightMax[i])-height[i]
        """

        n = len(height)
        res = 0

        # 处理特殊情况
        if n == 0:
            return res
    
        leftMax = list()
        rightMax = [0]*n    # 提前使用0进行占位,来避免列表本身的索引缺陷
        leftMax.append(height[0])
        rightMax[n-1] = height[n-1]   # 直接进行赋值覆盖
        # print(rightMax)

        for i in range(1, n):
            leftMax.append(max(leftMax[i-1], height[i]))
        # print(leftMax)
        
        for i in range(n-2, -1, -1):
            rightMax[i] = max(rightMax[i+1], height[i]) # 注意这里是直接赋值,不是插入
        # print(rightMax)

        for i in range(n):
            res += (min(leftMax[i], rightMax[i]) - height[i])
        
        return res
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

使用双指针方法

class Solution:
    def trap(self, height: List[int]) -> int:
        # 使用双指针简化空间复杂度
        n = len(height)
        res = 0

        if n == 0:
            return res

        # 定义两个指针
        left = 0
        right = n-1

        leftMax = 0
        rightMax = 0

        while left < right:
            leftMax = max(leftMax, height[left])
            rightMax = max(rightMax, height[right])
            # 使用两个指针,不断更新结果,边遍历,边计算
            if height[left] < height[right]:    # 一定有leftMax < RightMax
                res += (leftMax - height[left])
                left += 1
             """
             原因:
             单纯看存左到右计算:(建议画个图) 
             当 left < leftMax, 从左到右计算的话,这个时候leftMax必须小于right, left本位的水量才能一次性确定下
             来,就有left < leftMax < right <= rightMax,left += 1,否则的话,就会自动交给从右到左计算的那部
             分程序处理
             当 left == leftMax,从左到右计算的话,说明left本位是存不了水,这个时候left大于或者小于right都无所 
             谓(仅仅针对从左到右),但是left要移动,干脆让它小于right的情况下移动和上面保持一致就行了
             """
            else:
                res += (rightMax - height[right])
                right -= 1
        return res
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值