試題:盛最多水的容器
給定 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 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++) maxarea = Math.max(maxarea, Math.min(height[i], height[j]) * (j - i)); return maxarea; } }
複雜度分析
- 時間複雜度:O(n^2),計算所有n(n-1)/2種高度組合的面積
- 空間複雜度:O(1),使用恆定的額外空間。
方法二:雙指針法
這種方法背後的思路在於,兩線段之間形成的區域總是會受到其中較短那條長度的限制。此外,兩線段距離越遠,得到的面積就越大。
我們在由線段長度構成的數組中使用兩個指針,一個放在開始,一個置於末尾。 此外,我們會使用變量 maxareamaxarea 來持續存儲到目前為止所獲得的最大面積。 在每一步中,我們會找出指針所指向的兩條線段形成的區域,更新 maxareamaxarea,並將指向較短線段的指針向較長線段那端移動一步。
查看下面的例子將有助於你更好地理解該算法:
1 8 6 2 5 4 8 3 7
這種方法如何工作?
最初我們考慮由最外圍兩條線段構成的區域。現在,為了使面積最大化,我們需要考慮更長的兩條線段之間的區域。如果我們試圖將指向較長線段的指針向內側移動,矩形區域的面積將受限於較短的線段而不會獲得任何增加。但是,在同樣的條件下,移動指向較短線段的指針儘管造成了矩形寬度的減小,但卻可能會有助於面積的增大。因為移動較短線段的指針會得到一條相對較長的線段,這可以克服由寬度減小而引起的面積減小。
public class Solution { public int maxArea(int[] height) { int maxarea = 0, l = 0, r = height.length - 1; while (l < r) { maxarea = Math.max(maxarea, Math.min(height[l], height[r]) * (r - l)); if (height[l] < height[r]) l++; else r--; } return maxarea; } }
複雜度分析
- 時間複雜度:O(n),一次掃描。
- 空間複雜度:O(1),使用恆定的空間。
作者:LeetCode
鏈接:https://leetcode-cn.com/problems/container-with-most-water/solution/sheng-zui-duo-shui-de-rong-qi-by-leetcode/
來源:力扣(LeetCode)