题目:
给出一个整形数组,其中的元素为a1,a2,……an,现在在平面直角坐标系中作出点(i,ai),并与(i,0)连线,共形成n条线,现在任选两条线,可以个x轴形成一个容器,如果在这个容器中加水,如何选择n条线中的两条,才可以使得这两条线和x轴围成的容器装的水的面积更大。
Note:n大于1
举例:
1 8 6 2 5 4 8 3 7最大面积为( a 9*(9-2)) = 49,
思路:
将题目理解之后,就明白了,题目实际上是要求找i,j,使得|min(ai - aj)*(i - j)|最大,最容易想到的就是暴力搜索,将所有情况的i,j组合都找到,但是显然这种方法简单易懂,肯定不是一个比较优秀的方法。
以下是一个时间复杂度为O(n)的策略:
具体的计算过程请看https://leetcode.com/problems/container-with-most-water/solution
我们知道一个容器能装多少水是由最短的板决定的,在题目中的这个二维的容器中,能装多少水,则看的较短的那个边,同时也要考虑底部的长度。
对于某个i,j,计算|(ai - aj)*(i - j)|,和maxarea比较,并更新maxarea的值,如果ai < aj,则i++,否则j--。
在比较ai 和 aj的大小这一步,实际上相比于暴力搜索法省略掉了多步,在计算|(ai - aj)*(i - j)|时,假如ai < aj,那么此时计算ai和aj-1,ai和aj-1,……ai和ai+1对应的直线之间的面积已经没有意义。原因如下:对于i + 1 <= m <= j - 1,若am > ai,此时容器的高度为ai,|(ai - am)*(i - m)|的值显然小于|(ai - aj)*(i - j)|的值,若am < ai,此时容器的高度为am,而m <= j - 1,|(ai - am)*(i - m)|的值仍然小于|(ai - aj)*(i - j)|的值,所以此时计算|(ai - am)*(i - m)|的值已经没有意义。所以这个时间复杂度为O(n)的策略比暴力搜索法省去了好多步骤,并且求得结果是正确的。
代码:
public class Container_With_Most_Water {
public static int maxArea(int[] height)
{
int n = height.length;
int start = 0;
int end = n - 1;
int maxarea = 0;
while(end >= start)
{
maxarea = Math.max(maxarea, Math.abs((start - end)*(Math.min(height[start],height[end]))));
if(height[start] > height[end])
end--;
else
start++;
}
return maxarea;
}
public static void main(String[] args)
{
int[] height = {1,8,6,2,5,4,8,3,7};
System.out.println(maxArea(height));
}
时间复杂度:
只把数组遍历了一次,时间复杂度为O(n)。
空间复杂度:
O(1)。