每日一道 LeetCode (51):盛最多水的容器

每天 3 分鐘,走上算法的逆襲之路。

前文合集

每日一道 LeetCode 前文合集

代碼倉庫

GitHub: https://github.com/meteor1993/LeetCode

Gitee: https://gitee.com/inwsy/LeetCode

題目:盛最多水的容器

難度:中等

題目來源:https://leetcode-cn.com/problems/container-with-most-water/

給你 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。

示例:

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

解題思路

今天這道題蠻有意思的,給出一個數組,實際上是在求這個數組之間可以組成的最大面積。

這道題正統的解法是使用雙指針,因爲是在數組之間灌水,能容納的水有多少是取決於那個最小的數字,所以我們先把兩個指針分別指向數組的頭和尾,先求一下當前的面積,然後比較下頭尾的大小,每次移動較小的那個指針,把整個數組迭代一遍,取出其中的最大值即可。

public int maxArea(int[] height) {
    int len = height.length;
    int start = 0, end = len - 1;
    int maxArea = 0;
    while (start != end) {
        int area = Math.min(height[start], height[end]) * (end - start);
        maxArea = Math.max(area, maxArea);
        if (height[start] < height[end]) {
            start++;
        } else {
            end--;
        }
    }
    return maxArea;
}

代碼看起來不難,聲明一點哈,上面這個方案不是我想出來的,是看了答案的提示以後才知道的。

但是這裏面有個問題,爲什麼這種方案是可以找到最大的面積的,難道就不會存在其他的情況麼?

下面的這個證明方案同樣來自於答案當中,用來證明上面這個方案的正確性。

雙指針代表的是可以作爲容器邊界的所有位置的範圍。在一開始,雙指針指向數組的左右邊界,表示數組中所有的位置都可以作爲容器的邊界,因爲我們還沒有進行過任何嘗試。

在這之後,我們每次將對應的數字較小的那個指針往另一個指針 方向移動一個位置,就表示我們認爲這個指針不可能再作爲容器的邊界了。

那麼爲啥這個指針不能在作爲容器的邊界了,下面是這個問題的證明:

首先考慮第一步,假設當前左指針和右指針指向的數分別爲 x 和 y,先假設 x < y ,同時兩個指針之間的距離爲 t ,那麼他們組成的容器的容量爲:

min(x, y) * t = x * t

這時可以斷定,如果我們保持左指針的位置不變,那麼無論右指針在哪裏,這個容器的容量都不會超過 x * t 了。注意這裏右指針只能向左移動,因爲我們考慮的是第一步,也就是指針還指向數組的左右邊界的時候。

我們任意的移動右指針,指向的數字爲 y1 ,兩個指針之間的距離爲 t1 ,那麼顯然有 t1 < t ,並且 min(x, y1) <= min(x, y)

  • 如果 y1 <= y 那麼有 min(x, y1) <= min(x, y)
  • 如果 y1 > y 那麼有 min(x, y1) = x <= min(x, y)

因此剛纔上面的那個公式可推導:

min(x, y1) * t1 = min(x, y) * t 

即無論我們怎麼移動右指針,得到的容器的容量都小於移動前容器的容量。也就是說,這個左指針對應的數不會作爲容器的邊界了,那麼我們就可以丟棄這個位置,將左指針向右移動一個位置,此時新的左指針於原先的右指針之間的左右位置,纔可能會作爲容器的邊界。

這樣以來,我們將問題的規模減小了 11,被我們丟棄的那個位置就相當於消失了。此時的左右指針,就指向了一個新的、規模減少了的問題的數組的左右邊界,接下來,我們可以重複上面的這個過程,接着縮小容器邊界。

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