Leetcode - 接雨水问题

问题描述

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

在这里插入图片描述

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

分析

  1. 方法一:暴力解法;每个位置垂直求接水量,求出当前位置左右柱子的最高值。时间复杂度O(n2n^2),空间复杂度O(1)
  2. 方法二:动态编程;也是每个位置垂直求水量,我们用两次循环求得每个位置上的左右柱子的最高值。时间复杂度O(n), 空间复杂度O(n)。
  3. 方法三:单调栈;水平求接水量,利用单调递增栈,一遍可求得答案。时间复杂度O(n), 空间复杂度O(n)。
  4. 方法四:双指针法;每个位置垂直求接水量,利用双指针解决:是法二动态编程的优化,时间复杂度O(n),空间复杂度,O(1)。

代码

class Solution:
    # 暴力解法
    def trap1(self, height):
        res = 0
        length = len(height)
        for i in range(length):
            Lhigh = height[i]
            Rhigh = height[i]
            for j in range(length):
                if j < i:
                    Lhigh = max(Lhigh, height[j])
                elif j > i:
                    Rhigh = max(Rhigh, height[j])

            res += min(Lhigh, Rhigh) - height[i]

        return res

    # 动态编程
    def trap2(self, height):

        length = len(height)
        maxNum = 0
        Rhigh = []
        Lhigh = [0] * length
        for i in range(length):
            maxNum = max(maxNum, height[i])
            Rhigh.append(maxNum)

        maxNum = 0
        for i in range(length-1, -1, -1):
            maxNum = max(maxNum, height[i])
            Lhigh[i] = maxNum

        res = 0
        for i in range(length):
            res += min(Rhigh[i], Lhigh[i]) - height[i]

        return res

    # 单调栈
    def trap3(self, height):
        if not height:
            return 0

        # 单调递增栈
        stack = []
        current = 0
        length = len(height)
        res = 0

        while current<length:
            while stack and height[stack[-1]] < height[current]:
                cur_index = stack.pop()
                if stack: # 形成水平低洼处
                    cur_bound = current - stack[-1] - 1 # 低洼宽度
                    cur_height = min(height[current], height[stack[-1]]) - height[cur_index] # 低洼高度
                    res += cur_bound * cur_height
            stack.append(current)
            current += 1

        return res

    # 双指针法 法二 动态编程推广
    def trap(self, height):
        if not height:
            return 0

        maxL = 0
        maxR = 0
        pleft = 0
        pright = len(height) - 1
        res = 0

        while pleft<pright:
            if height[pleft]<height[pright]:
                if height[pleft] < maxL:
                    res += maxL - height[pleft]
                else:
                    maxL = height[pleft]
                pleft += 1
            else:
                if height[pright] < maxR:
                    res += maxR - height[pright]
                else:
                    maxR = height[pright]
                pright -= 1

        return res





if __name__ == '__main__':
    height = [0,1,0,2,1,0,1,3,2,1,2,1]

    test = Solution()

    res = test.trap(height)

    print(res)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章