[题目]
Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
[中文翻译]
给定n个非负整数a1,a2,…,an,其中每个表示坐标(i, ai)处的点。 绘制n条垂直线,每条线的两个端点为(i, ai)和(i, 0)。 找到两条线,它们与x轴一起形成一个容器,使得容器包含最多的水。
注意:您不能倾斜容器,n至少为2。
[解题思路]
朴素的解法,枚举两条线的组合,然后计算出面积最大的一组,效率为O(n2)。
但实际上,有很多组合是可以不需要枚举的。
如图,红色的两条线,是当前枚举的组合,绿色区域是容器能包含的水。那么,在两条红线中间的线,任意一条与短的那条红线形成的新的组合,所能包含的水一定不会超过绿色区域。因为短的那条红线决定了最高的高度,而宽度不会比绿色区域的宽度更宽。因此,假设已考虑过两条红线之外的黑线,那么之后的枚举过程中,短红线已经可以移除,因为存在短红线的组合已经不可能是最优解。
至此,我们可以得到一个O(n)的算法,用两条线表示当前枚举到的组合,初始时是最左和最右两条线,然后依次将短的一条移除,用内部最靠近它的线代替,得到新的枚举组合。这样的枚举,可以保证不会遗漏最优解,因为没有枚举到的组合都不会是最优解。然后计算这些枚举到的组合中,面积最大的一组即可。
[C++代码]
class Solution {
public:
int maxArea(vector<int>& height) {
int max = 0, now;
int hl, hr;
int l, r, len;
l = 0; r = height.size() - 1;
len = height.size() - 1;
while (l < r) {
hl = height.at(l); hr = height.at(r);
if (hl < hr) {
now = hl*len;
l++;
}
else {
now = hr*len;
r--;
}
if (now > max)
max = now;
len--;
}
return max;
}
};