11. 盛最多水的容器 Container With Most Water
Givenn
non-negative integersa1, a2, ..., an
, where each represents a point at coordinate(i, ai)
.n
vertical lines are drawn such that the two endpoints of the linei
is at(i, ai)
and(i, 0)
. Find two lines, which, together with the x-axis forms a container, such that the container contains the most water.
Noticethat you may not slant the container.
Input: height = [1,8,6,2,5,4,8,3,7]
Output: 49
Explanation: The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.
雙指標法
證明
為什麼雙指標的做法是正確的?
雙指標代表了什麼?
雙指標代表的是 可以作為容器邊界的所有位置的範圍。在一開始,雙指標指向陣列的左右邊界,表示 陣列中所有的位置都可以作為容器的邊界,因為我們還沒有進行過任何嘗試。在這之後,我們每次將 對應的數字較小的那個指標 往 另一個指標 的方向移動一個位置,就表示我們認為 這個指標不可能再作為容器的邊界了。
為什麼對應的數字較小的那個指標不可能再作為容器的邊界了?
在上面的分析部分,我們對這個問題有了一點初步的想法。這裡我們定量地進行證明。考慮第一步,假設當前左指標和右指標指向的數分別為 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,yt)∗t1<min(x,y)∗t
即無論我們怎麼移動右指標,得到的容器的容量都小於移動前容器的容量。也就是說,這個左指標對應的數不會作為容器的邊界了,那麼我們就可以丟棄這個位置,將左指標向右移動一個位置,此時新的左指標於原先的右指標之間的左右位置,才可能會作為容器的邊界。
這樣以來,我們將問題的規模減小了
1,被我們丟棄的那個位置就相當於消失了。此時的左右指標,就指向了一個新的、規模減少了的問題的陣列的左右邊界,因此,我們可以繼續像之前 考慮第一步 那樣考慮這個問題:
求出當前雙指標對應的容器的容量;
對應數字較小的那個指標以後不可能作為容器的邊界了,將其丟棄,並移動對應的指標。
最後的答案是什麼?
答案就是我們每次以雙指標為左右邊界(也就是「陣列」的左右邊界)計算出的容量中的最大值。
public int maxArea(int[] height) { int l = 0; int r = height.length - 1; int ans = 0; while(l <= r ){ int min = Math.min(height[l], height[r]); ans = Math.max(ans, min * (r - l)); if (height[l] < height[r]) l++; else r--; } return ans; }
時間複雜度O(N)
參考連結:
https://leetcode.com/problems/container-with-most-water/
https://leetcode-cn.com/problems/container-with-most-water