【刷穿 LeetCode】11. 盛最多水的容器(中等)
技術標籤:刷穿 LeetCode演算法資料結構leetcode面試貪心演算法
題目描述
給你 n
個非負整數 a1,a2,...,an
,每個數代表座標中的一個點 (i, ai)
。在座標內畫 n
條垂直線,垂直線 i
的兩個端點分別為 (i, ai)
和 (i, 0)
。找出其中的兩條線,使得它們與 x
軸共同構成的容器可以容納最多的水。
說明:你不能傾斜容器。
示例 1:
輸入:[1,8,6,2,5,4,8,3,7]
輸出:49
解釋:圖中垂直線代表輸入陣列 [1,8,6,2,5,4,8,3,7]。
在此情況下,容器能夠容納水(表示為藍色部分)的最大值為 49。
示例 2:
輸入:height = [1,1] 輸出:1
示例 3:
輸入:height = [4,3,2,1,4]
輸出:16
示例 4:
輸入:height = [1,2,1]
輸出:2
提示:
n = height.length
2 <= n <= 3 * 104
0 <= height[i] <= 3 * 104
樸素解法
我們可以直接列舉所有的情況:先列舉確定左邊界,再往右列舉確定右邊界。
然後再記錄列舉過程中的最大面積即可:
class Solution {
public int maxArea(int[] height) {
int n = height.length;
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int w = j - i;
int h = Math.min(height[i], height[j]);
ans = Math.max(w * h, ans);
}
}
return ans;
}
}
時間複雜度:
O
(
n
2
)
O(n ^ 2)
空間複雜度: O ( 1 ) O(1) O(1)
雙指標+貪心解法
先用兩個指標 i
和 j
指向左右邊界,然後考慮指標應該怎麼移動。
由於構成矩形的面積,取決於 i
和 j
之間的距離(記為 w
) 和 i
和 j
下標對應的高度的最小值(記為 h
)。
首先無論是 i
指標往右移動還是 j
指標往左移動都會導致 w
變小,所以想要能夠列舉到更大的面積,我們應該讓 h
在指標移動後變大。
不妨假設當前情況是 height[i] < heigth[j]
(此時矩形的高度為 height[i]
),然後分情況討論:
-
讓
i
和j
兩者高度小的指標移動,即i
往右移動:- 移動後,i 指標對應的高度變小,即
height[i] > height[i + 1]
:w
和h
都變小了,面積一定變小 - 移動後,i 指標對應的高度不變,即
height[i] = height[i + 1]
:w
變小,h
不變,面積一定變小 - 移動後,i 指標對應的高度變大,即
height[i] < height[i + 1]
:w
變小,h
變大,面積可能會變大
- 移動後,i 指標對應的高度變小,即
-
讓
i
和j
兩者高度大的指標移動,即j
往左移動:- 移動後,j 指標對應的高度變小,即
height[j] > height[j - 1]
:w
變小,h
可能不變或者變小(當height[j - 1] >= height[i]
時,h
不變;當height[j - 1] < height[i]
時,h
變小),面積一定變小 - 移動後,j 指標對應的高度不變,即
height[j] = height[j - 1]
:w
變小,h
不變,面積一定變小 - 移動後,j 指標對應的高度變大,即
height[j] < height[j - 1]
:w
變小,h
不變,面積一定變小
- 移動後,j 指標對應的高度變小,即
綜上所述,我們只有將高度小的指標往內移動,才會列舉到更大的面積:
class Solution {
public int maxArea(int[] height) {
int n = height.length;
int i = 0, j = n - 1;
int ans = 0;
while (i < j) {
ans = Math.max(ans, (j - i) * Math.min(height[i], height[j]));
if (height[i] < height[j]) {
i++;
} else {
j--;
}
}
return ans;
}
}
時間複雜度:會對整個陣列掃描一遍。複雜度為 O ( n ) O(n) O(n)
空間複雜度: O ( 1 ) O(1) O(1)
最後
這是我們「刷穿 LeetCode」系列文章的第 No.11
篇,系列開始於 2021/01/01,截止於起始日 LeetCode 上共有 1916 道題目,部分是有鎖題,我們將先將所有不帶鎖的題目刷完。
在這個系列文章裡面,除了講解解題思路以外,還會盡可能給出最為簡潔的程式碼。如果涉及通解還會相應的程式碼模板。
由於 LeetCode 的題目隨著周賽 & 雙週賽不斷增加,為了方便我們統計進度,我們將按照系列起始時的總題數作為分母,完成的題目作為分子,進行進度計算。當前進度為 11/1916
。
為了方便各位同學能夠電腦上進行除錯和提交程式碼,我建立了相關的倉庫:Github 地址 & Gitee 地址。
在倉庫地址裡,你可以看到系列文章的題解連結、系列文章的相應程式碼、LeetCode 原題連結和一些其他的優選題解。
#演算法與資料結構
#LeetCode題解
#演算法面試