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.
方法一:穷举
超时。
方法二:
对题目的数学性质进行分析,发现:
1)对于最大容量的桶的左侧,设其横坐标为l。则al大于其左端任意一条竖线。
2)同理,对于最大桶的右侧,设其横坐标为r。则ar大于其右端任意一条竖线。
我就不证明了,用反证法即可。
这就对程序的实现提供了一条思路:每次从桶的一侧往中间收缩。收缩时,直到找到比当前高度更高的一条竖线时,才进行计算是否桶的容量有所增加。
采取这种两边往中间靠的方式,需要注意的有两点:
1)每次从当前较短的一条边进行往中间收缩。如果从较长的边进行收缩,则受制于另一条较短的边,新计算的容量总是会更小。
2)当收缩到左侧边横坐标等于右侧边横坐标时,循环结束。但为什么此时得出的最大容量就是最终的答案,它是否包含了所有需要考虑的情况?我没有进行严格的数学证明,只是程序通过了LeetCode平台的45个测试案例。
不过在csdn上看到一种解释:容积即面积,它受长和高的影响,当长度减小时候,高必须增长才有可能提升面积,所以我们从长度最长时开始递减,然后寻找更高的线来更新候补;
受到启发,这样来说服自己:这种方法从底边最长的长度开始,递减收缩至底边最短的长度,且在收缩过程中,容量是在不断的更大化。从底边的长度角度来看,其覆盖了所有的情况。
C语言代码如下:
<strong>int maxArea(int* height, int heightSize) {
int left = 0, right = heightSize - 1;
int volume = 0;
int tmpVolume;
int k;
while(left < right)
{
tmpVolume = (height[left] < height[right] ? height[left] : height[right]) * (right - left);
volume = tmpVolume > volume ? tmpVolume : volume;
if(height[left] < height[right])
{
k = left;
while(height[k] <= height[left] && k < right)
k++;
left = k;
}
else
{
k = right;
while(height[k] <= height[right] && k >left)
k--;
right = k;
}
}
return volume;
};
</strong>