给你n个非负整数a1, a2, ...an,每一个代表一个坐标(i, ai)。有n条垂线画在画布上,两个端点分别是(i, ai) 和(i, 0)。
请找出两条线,这两条线与x轴形成一个容器,这个容器中包含尽肯能多的水。
注意:你不必把它当成容器,n至少是2。
1. 暴力法 (Time Limit Exceeded)
逐个计算每一个container的面积,找出面积最大的。
public int maxArea(int[] height)
{
int ans = 0;
int maxArea = 0;
int area = 0;
int i = 0, j = 1;
int step = 1; // 步数
for (i=0; i<height.length; i++)
{
if (j < height.length)
{
int high = Math.min(height[i], height[j]); // 容器的高度
area = high * step;
if (area > maxArea)
maxArea = area;
j++; // 更新j的值
}
else
{
step++; // 步幅加1
i = -1;
j = 0;
j += step;
}
// 当步幅变为最大宽度时,退出循环
if (step == height.length)
{
break;
}
}
ans = maxArea;
return ans;
}
精简的代码:
public class Solution {
public int maxArea(int[] height) {
int maxarea = 0;
for (int i = 0; i < height.length; i++)
for (int j = i + 1; j < height.length; j++)
maxarea = Math.max(maxarea, Math.min(height[i], height[j]) * (j - i));
return maxarea;
}
}
时间复杂度:O(n^2)
空间复杂度:O(1)
2. 双指针法
我们取两个指针,一个放在开头,一个放在数组的末尾;然后我们用一个变量maxarea来存储到目前为止最大的面积。
在每一步中,我们可以找到它们之间形成的区域的面积,不断更新maxarea的值,并将指针指向较短的那条线。
步骤:
一开始,我们先考虑最外面的线条构成的区域。为了使面积最大化,我们需要考虑更长的线所围成的区域的面积。
如果我们试图把指针移动到较长的线内,我们就不会得到任何面积的增加,因为它受到短线的限制。
同理,移动较短的线的指针可能是有利的,尽管宽度会有所减少。这是由于相对于移动较长的线而言,移动指向
较短的线段的指针,可以克服由于宽度减少而造成的面积减少。
public int maxArea(int[] height)
{
int maxArea = 0;
int left = 0;
int right = height.length-1;
while (left < right)
{
maxArea = Math.max(maxArea, Math.min(height[left], height[right]) * (right-left));
if (height[left] < height[right])
left++;
else
right--;
}
return maxArea;
}
时间复杂度: O(n)
空间复杂度: O(1)