來源:力扣(LeetCode)
連接:https://leetcode-cn.com/probl...數組
給定 n 個非負整數 a1,a2,...,an,每一個數表明座標中的一個點 (i, ai) 。在座標內畫 n 條垂直線,垂直線 i 的兩個端點分別爲 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構成的容器能夠容納最多的水。spa
說明:你不能傾斜容器,且 n 的值至少爲 2。指針
圖中垂直線表明輸入數組 [1,8,6,2,5,4,8,3,7]。在此狀況下,容器可以容納水(表示爲藍色部分)的最大值爲 49。code
示例:blog
輸入: [1,8,6,2,5,4,8,3,7] 輸出: 49
題解:遞歸
看到這題,像我這樣的通常第一時間想到的就是暴力法,雙層循環,列舉出全部的可能性,而後選出最大的一個值。ip
/** * @param {number[]} height * @return {number} */ var maxArea = function(height) { let newS = 0; for(let i = 0; i < height.length;i++){ for(let j = i+1;j<height.length;j++){ newS = Math.max(newS,Math.min(height[i],height[j])*(j-i)) } } return newS; };
時間複雜度:O(n^2),計算全部 n(n−1)/2種高度組合的面積。內存
空間複雜度:O(1),使用恆定的額外空間。leetcode
執行用時 :948 ms, 在全部 JavaScript 提交中擊敗了29.18%的用戶rem
內存消耗 :35.3 MB, 在全部 JavaScript 提交中擊敗了73.30%的用戶
明顯能夠感覺到暴力法通常都不是最優解。
矩形的面積是長和寬相乘,若是要面積大,那麼長和寬要儘量的長。
在這題裏,矩形的寬就是h(i)
和h(j)
的距離,就是(j-i)
,而寬則是h(i)
和h(j)
中較短的那一條。那麼要面積儘量的大,就須要Math.min(h(i),h(j))
儘可能大,(j-i)
儘可能大。
咱們設置兩個指針 left
和 right
,分別指向數組的最左端和最右端。此時,兩條垂直線的距離是最遠的,若要下一個矩陣面積比當前面積來得大,必需要把 height[left]
和 height[right]
中較短的垂直線往中間移動,看看是否能夠找到更長的垂直線。
由於將較長的那根垂直線往中間移動,面積只會減少,因此移動較短的那根。
將全部的狀況用遞歸樹列出來,以下圖:
數組是 [1,8,6,2,5,4,8,3,7]
指針在兩端,沒進行一次比較就能劃去一列不可能的選項。以下圖,當比較第一次的時候,h(0)h(8)比較,此時的面積是h(0)*(8-0)=8,那麼就須要劃掉跟0相關的那一列,由於那一列的面積確定只會比8小。以下圖:
而後比較下一級h(1)和h(8),從而得出面積是49,由於h(1)>h(8),因此能夠劃去跟h(8)相關的一列,由於面積不管怎麼樣都會小於(1,8),以下圖
以此類推,最終獲得一條路線。
在比較的時候就把最大值存入一個變量中,而後在結束的時候返回就行。
var maxArea = function(height) { let maxS = 0; let i = 0,j = height.length-1; while(i < j){ maxS = Math.min(height[i],height[j])*(j-i)>maxS?Math.min(height[i],height[j])*(j-i):maxS; height[i] <= height[j] ? i++ : j-- } return maxS; };
執行用時 :64 ms, 在全部 JavaScript 提交中擊敗了97.97%的用戶
內存消耗 :35.2 MB, 在全部 JavaScript 提交中擊敗了85.63%的用戶