Python Leetcode接雨水

题目如图所示:
在这里插入图片描述
对于该题,从以下几个方法展开求解。

1.暴力求解

直接按问题描述进行。对于数组中的每个元素,我们找出下雨后水能达到的最高位置,等于两边最大高度的较小值减去当前高度的值。

时间复杂度为O(n2),空间复杂度为O(1)。

class Solution:
    def trap(self, height: List[int]) -> int:
        length = len(height)
        res = 0
        for i in range(1, length - 1):
            max_left = 0
            max_right = 0
            for j in range(0, i+1):
                max_left = max(height[j], max_left)
            for k in range(i, length):
                max_right = max(height[k], max_right)
            res += (min(max_right, max_left) - height[i])
        return res

改暴力求解并不能通过,时间超时。但如果对内部的两个for循环进行切片数组求最大值操作,则可以成功通过。代码如下:

class Solution:
    def trap(self, height: List[int]) -> int:
        length = len(height)
        res = 0
        for i in range(1, length - 1):
            max_left = 0
            max_right = 0    
            max_left = max(height[:i+1])
            max_right = max(height[i:])
            res += (min(max_right, max_left) - height[i])
        return res

运行时间大概为1816ms,时间还是很长,但相比上一个代码,已经可以成功提交了。

2.动态编程

在暴力方法中,我们仅仅为了找到最大值每次都要向左和向右扫描一次。但是我们可以提前存储这个值。因此,可以通过动态编程解决。

1.时间复杂度为O(n):
存储最大高度数组,需要两次遍历,每次 O(n),
2.空间复杂度为O(n):
使用了额外的 O(n)空间用来放置 left_max 和 right_max 数组。

class Solution:
    def trap(self, height: List[int]) -> int:
        if not height:
            return 0
        res = 0
        length = len(height)
        left_max = [0 for _ in range(length)]
        right_max = [0 for _ in range(length)]

        left_max[0] = height[0]
        for i in range(1, length):
            left_max[i] = max(left_max[i-1], height[i])
        
        right_max[length - 1] = height[length - 1]
        for i in range(length - 2, -1, -1):
            right_max[i] = max(right_max[i + 1], height[i])
        
        for i in range(1, length - 1):
            res += min(left_max[i], right_max[i]) - height[i]
        
        return res

3.栈的应用

我们可以不用像方法 2 那样存储最大高度,而是用栈来跟踪可能储水的最长的条形块。使用栈就可以在一次遍历内完成计算。

我们在遍历数组时维护一个栈。如果当前的条形块小于或等于栈顶的条形块,我们将条形块的索引入栈,意思是当前的条形块被栈中的前一个条形块界定。如果我们发现一个条形块长于栈顶,我们可以确定栈顶的条形块被当前条形块和栈的前一个条形块界定,因此我们可以弹出栈顶元素并且累加答案到 res。

#应用栈
class Solution:
    def trap(self, height: List[int]) -> int:
        res = 0
        length = len(height)
        if length < 3: return 0
        index = 0
        stack = []
        while index < length:
            while len(stack) > 0 and height[index] > height[stack[-1]]:
                top = stack.pop()
                if len(stack) == 0:
                    break
                w = index - stack[-1] - 1
                h = min(height[index], height[stack[-1]]) - height[top]
                res += (w*h)
            stack.append(index)
            index += 1
        return res

1.时间复杂度O(n):
单次遍历O(n),每个条形最多访问两次(由于栈的弹入和弹出),并且弹入和弹出栈都是O(1)的。
2.空间复杂度为O(n):
栈最多在阶梯型或平坦型的条形块结构中占用O(n)的空间。

4.双指针

和方法 2 相比,我们不从左和从右分开计算,我们想办法一次完成遍历。
我们可以认为如果一端有更高的条形块(例如右端),积水的高度依赖于当前方向的高度(从左到右)。当我们发现另一侧(右侧)的条形块高度不是最高的,我们则开始从相反的方向遍历(从右到左)。
我们必须在遍历时维护left_max 和 right_max ,但是我们现在可以使用两个指针交替进行,实现 1 次遍历即可完成。

#双指针
class Solution:
    def trap(self, height: List[int]) -> int:
        l, r = 0, len(height) - 1
        res = 0
        left_max, right_max = 0, 0
        while l < r:
            if height[l] < height[r]:
                if height[l] >= left_max:
                    left_max = height[l]
                else:
                    res += left_max - height[l]
                l += 1
            else:
                if height[r] >= right_max:
                    right_max = height[r]
                else:
                    res += right_max - height[r]
                r -= 1
        return res

1.时间复杂度O(n):单次遍历的时间O(n);
2.空间复杂度O(1):l,r,left_max,right_max只需要常数的空间。

双指针的另一种解法思路

class Solution:
    def trap(self, height: List[int]) -> int:
        l, r = 0, len(height) - 1
        res = 0
        temp_h = 0
        while l <= r:
            min_h = min(height[l], height[r])
            if min_h > temp_h:
                res += (min_h - temp_h) * (r - l + 1)
                temp_h = min_h
            while l <= r and height[l] <= temp_h:
                l += 1
            while l <= r and height[r] <= temp_h:
                r -= 1
        res -= sum(height)
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值