LeetCode數組篇(六):盛最多水的容器

題目:盛最多水的容器

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

道人第一想法就是暴力求解

這裏道人說明下,暴力求解並沒什麼不好;道人解釋下原因和自己的理解。

  • 首先:計算機就是做運算的,就是擅長做重複的邏輯計算,以現在計算機的性能,一些在你眼中的高時間複雜度的工作,也許效率並不是你想象的那麼低。
  • 如果說第一個原因你說有些牽強,那麼下面兩個原因,也許能爲暴力求解找出合理的解釋。
    • 數據量不大:在業務場景(數據量不大)的情況下,O(n)與O(n二次方)的差距並不大。
    • 代碼可讀性強:相對而言,暴力求解算是很容易被不同的人理解的。
    • 方便理清邏輯:暴力求解,其實是幫我們理清最基礎的邏輯,在理清基礎邏輯後,如何優化?如何轉換角度?如何提高性能?暴力求解都給我們奠定了優化該題的基礎。

暴力求解:任意兩點(ai,aj)的容器容積的計算公式Math.min(ai,aj)*(j-i)。

代碼如下

class Solution {
    public int maxArea(int[] height) {
        // 暴力求解
        int maxArea = 0;
        for (int i = 0; i < height.length; i++){
            for(int j = i+1; j < height.length; j++){
                if (Math.min(height[i],height[j])*(j-i) > maxArea){
                    maxArea = Math.min(height[i],height[j])*(j-i);
                }
            }
        }
        return maxArea;
    }
}

第二思路: 雙向指針(排除了很多明顯小於當前容積的情況)

核心:選取最左、最右兩個指針,實際上是獲取了以較小高度爲一邊的所有容器的最大容積!!!!剔除了中間的很多明顯小於當前容積的情況!!!

從頭到尾遍歷必須再次嵌套一層循環,那麼從尾到頭遍歷啦?或者雙向指針一起遍歷?會是什麼結果。

分析思路:

  • 不難發現暴力求解存在着大量的重複計算。
    以i=0該點爲例,假若height[i]爲較低的一點,那麼高度則以height[i]爲基準,最大容積與長度相關則height[height.length-1]爲構成的最大容積(以i=0該點爲一邊的容積)。
  • 若我們以height左右兩邊爲起點,以兩邊較小值爲一邊,便是此時最大容積;**那麼怎麼移動纔可能使下一個容積大於當前容積?**較大一邊的指針向中間移動?由於底邊減少,那麼容積要想大於原來的值,高度必須大於原高度,那麼由於移動的較大一邊的指針,所以此時高度由原來的較小高度一邊限制,因此不可能大於原容積。
  • 所以,移動兩邊中較小高度一邊的指針,纔有可能在接下來的比較中獲取到比原來更大的容積。

上述邏輯的演示:(記住一點只有較小高度一邊的指針移動,新的容器值纔可能大於上一個容器值;同時你每次獲取的均是以較小邊爲容器一邊的最大值)

代碼如下:

class Solution {
    public int maxArea(int[] height) {
        // 雙指針求解法
        int maxArea = 0;
        int i = 0;
        int j = height.length-1;
        while( j > i){
            // 計算當前的最大容器值
            maxArea = Math.max(Math.min(height[j],height[i])*(j-i),maxArea);
            // 較小一邊的指針移動
            if (height[j] > height[i]){
                i++;
            } else {
                j--;
            }
        }
        return maxArea;
    }
}

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