給定 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
笨方法
既不是單純的找寬度最寬的兩點,也不是找高度最高的兩點,而是要找高*寬最大的參數。暴力搜索肯定是一種解決方案,但絕不是效率最高的方式。最好是能夠線性搜索。
能否用遞歸的思想解決,或者用二分法解決?遞歸看起來不怎么靠譜,因為局部能夠容納的最多水量與總體水量沒有必然關系。二分法似乎也不行,如果所有的矮柱子都分布在左邊,所有的高柱子都分布在右邊,而高柱子又遠遠高于矮柱子,這時最大容水量的矩形應該在右側。
先用暴力搜索來處理吧,處理過程中應當注意:index和value都需要用到。考慮到兩兩柱子的匹配存在重復,應可減少一半的比對時間。
代碼倒是挺簡單的,但是執行效率肯定不高。時間復雜度O(n^2),果然超時了。
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
area=0
for i,c in enumerate(height):
for i1,c1 in enumerate(height):
if i1>i and (i1-i)*min(c,c1)>area:
area=(i1-i)*min(c,c1)
return area
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
area=0
l=len(height)
for i,c in enumerate(height):
for j in range(i+1,l,1):
area=max(area,(j-i)*min(c,height[j]))
return area
聰明方法
采用官方題解中的雙指針法,其基本原理是:左右兩端各一個指針,如果其中一端的長度小于另一端的長度,則移動較短的那一端。因為容器的容量受較短的那個線段影響,而不會受較長的線段影響。每次移動都記錄當前的最大面積。
相對于笨方法,此方法的核心提升點在于:用了雙指針。移動指針的時候,可以比較兩個線段的長度后,再決定移動哪一個。
向內移動較長的線段時,由于寬度減少了,最短線段的長度不可能增加,因此總面積必然減少。所以,只需要向內移動較短的線段就行了,盡管寬度也減少了,但最短線段的長度可能會增加,從而導致總面積可能增加。
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
area=0
l,r=0,len(height)-1
while l<r:
area=max(area,(r-l)*min(height[l],height[r]))
if height[l]<height[r]:
l+=1
else:
r-=1
return area