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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章