「青训营 X 码上掘金」主题4:攒青豆

131 阅读2分钟

当青训营遇上码上掘金

以示例图为例,输入数组为[5,0,2,1,4,0,1,0,3],输出为17,下面是我的运行结果: image.png image.png 本题与力扣42题接雨水相同,详情可见42. 接雨水 - 力扣(LeetCode),这里给出其中一种解法。 我们可以先求出每一列左边或者右边最高墙的最小值,求左右两边的最高墙我们可以采用动态规划的方法来减小时间复杂度,具体如下:

求左边最高值

因为墙高最小为0,所以left_max数组的初始值可以全部设为0,然后从左往右遍历,第i列左边最高墙等于第i-1列左边最高墙和第i-1列墙的高度中更高的那一个,状态转移方程为left_max[i] = max(left_max[i-1], height[i-1]),为了防止越界,遍历范围设置为[1, n-2],最后一列不考虑的原因是最后一列一定不能接到豆子。

求右边最高值

该方法与求左边最高值方法类似,区别在于要从右往左遍历,状态转移方程为right_max[i] = max(right_max[i+1], height[i+1]),区间设置在[n-2, 0]。

求出左右两边的最高柱子高度后用mini表示两者中更小的一项,由图我们可以看出当mini>heght[i]时,第i列能接到的豆子数量等于mini-height[i],当mini<=height[i]时第i列接不到豆子,所以我们可以用ans += mini - height[i]来统计最终数量,最终返回的ans即为所求。

def trap(height: list[int]) -> int:
        n = len(height)
        ans = 0
        left_max = [0] * n
        right_max = [0] * n
        # 动态规划求左边最高柱子数组,left_max[i]表示第i列左边的最高柱子
        for i in range(1,n-1):
            left_max[i] = max(left_max[i-1], height[i-1])
        # 动态规划求右边最高柱子数组,right_max[i]表示第i列右边的最高柱子
        for i in range(n-2, -1, -1):
            right_max[i] = max(right_max[i+1], height[i+1]),
        # 求总的接豆子量,因为最左和最右不可能接到豆所以循环范围为从1到n-1
        for i in range(1, n-1):
            mini = min(left_max[i], right_max[i])
            # 当mini>height[i]时,第i列的接豆量为两者之差,当mini<=heght[i]时,第i列的接豆量为0
            if mini > height[i]:
                ans += mini - height[i]
        return ans

height = [4,2,0,3,2,5]
print(trap(height))