每天一道算法題(2020.06.09)-最多盛水容器

題目描述

給你 n 個非負整數 a1,a2,…,an,每個數代表座標中的一個點 (i, ai) 。在座標內畫 n 條垂直線,垂直線 i 的兩個端點分別爲 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。

說明:你不能傾斜容器,且 n 的值至少爲 2。

示例

輸入:[1,8,6,2,5,4,8,3,7]
輸出:49

思路

算法流程: 設置雙指針 i,j分別位於容器壁(數組)兩端,根據規則移動指針,並且持續更新面積最大值 res,直到 i == j 時返回 res。

那麼,關鍵問題在於,如何移動指針呢?

設每一狀態下水槽面積爲 S(i,j),(0<=i<j<n),需要明確的一點是,水槽的實際高度由兩板中的短板決定,則可得面積公式 S(i,j)=min(h[i],h[j])×(j−i)S(i, j) 。
在每一個狀態下,無論長板或短板所在指針向內走 1格,都會導致水槽 底邊寬度 −1,可分爲兩種情況:

  • 若短板所在指針向內移動,水槽的短板 min(h[i],h[j])可能變大,因此水槽面積 S(i,j)可能增大。
  • 若長板所在指針向內移動,水槽的短板 min(h[i],h[j]),下個水槽的面積一定小於當前水槽面積。

因此,長板所在指針向內移動的情況可以不做試驗。

在暴力枚舉的情況下,所有可能出現的 S(i,j) 的狀態數爲 C(n,2)。
現在,在狀態 S(i,j)下向內移動短板所在指針至 S(i+1,j)(假設 h[i]<h[j]),則相當於消去了 {S(i, j - 1), S(i, j - 2), … , S(i, i + 1)}狀態集合。而所有消去狀態的面積一定 <=S(i,j),因此,每次向內移動短板所在指針,所有的消去狀態都不會導致丟失面積最大值 。

代碼

class Solution:
    def max_area(self, height: List[int]) -> int:
        i, j, res = 0, len(height) - 1, 0
        while i < j:
            if height[i] < height[j]:
                res = max(res, height[i] * (j - i))
                i += 1
            else:
                res = max(res, height[j] * (j - i))
                j -= 1
        return res
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章