问题:给定 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。
Example:
Input: [1,8,6,2,5,4,8,3,7]
Output: 49
方法一:暴力解法
题目的意思其实就是找到一对(x1,y1)、(x2,y2)(假设x2 >x1),使得(x2 - x1)*min(y1,y2)最大。那么暴力的方法就是从第一个坐标开始,以它为基准,把其后每个坐标都与它作为一对值,进行一次计算,保留最大结果。之后再以第二个为基准,直到倒数第二个为止。找出其中最大的那个结果。时间复杂度是O(n)。这个算法在Python下是超时的,仅做参考。
#Python
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
h = height #替代一下,后面方便使用
res,temp = 0,0
for i in range(len(h)-1): #分别以每个高为基准,即第一个坐标
for j in range(i+1,len(h)): #第二个坐标
temp = (j-i) * min(h[i],h[j]) #求结果
res = max(temp,res) #保留最大结果
return res
方法二:动态法
我们可以看出,所求结果其实是两个坐标及其高度所围成的面积,而面积受横向的长度(x2 - x1)和纵向的高度(min(y1,y2))决定,有点类似于“木桶原理”,只不过我们这里底部也是在变化的。假设在高度不变的情况下,长度越长,面积越大,因此我们从最大长度开始计算(即左端和右端),然后再逐步缩小长度,因为长度虽然缩小了,但是高度可能会增加很多,导致最终结果可能会变大。在缩小长度的时候,每次只能从一边缩小一个单位,那究竟从哪边缩小呢?我们注意到在两个高度中,影响最终结果的是较小的那个高度,所以我们移动较小高度的那个点。这样一直到底部长度为1,整个比较结束。
#Python
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
i,j = 0,len(height) - 1 #设置左右端点
maxArea = 0 #保存最大结果
while i < j:
temp = (j-i) * min(height[i],height[j]) #计算本次结果
maxArea = max(maxArea,temp) #变更最终结果
if height[i] >= height[j]: #哪个高度小就从哪边移动
j -= 1
else:
i += 1
return maxArea
//C++
class Solution {
public:
int maxArea(vector<int>& height) {
int i = 0,j = height.size() - 1;
int res = 0;
while(i < j){
int temp = (j-i) * min(height[i],height[j]);
res = max(res,temp);
if(height[i] >= height[j])
j--;
else
i++;
}
return res;
}
};