题目:
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.
解法:一看题目就知道,普通的遍历只会TLE,优先考虑动态规划法减少复杂度,理论上可以降至O(n)。指针同时从首尾向中间逼近,当j<=i时,循环终止
设(ai,aj)为面积,那么由观察可以知道,若a(i+1)<=a(i),那么(a(i+1),aj)< (ai,aj),同理,若a(j-1)<= a(j),那么(a(i),a(j-1))< (a(i),a(j)),这些比较是多余的,我们只需要在相对于基点较大的i,j做一下判断足矣。
如果直接这样做,那么难道我们要每一个增大点都比较一次么,形如1,2,3,4,4,3,2,1的序列,实际上并没有降低复杂度。仍需要观察。
以2,3,10,5,7,8,9为例,按照上述比较方法,依次比较的点为(2,9)(2,10)(3,9)(3,10)(10,9),这样一看就很清楚了,(2,10)(3,10)这两次是完全不需要的,因为对于ai<aj的情况,容器的的高度取决于ai,因此j--的变化只会使得容器体积更小。于是我们可以改进条件:
若ai<aj,则i移动到最近的下一个大于ai的点,比较一次;
若ai>aj,则j移动到最近的下一个大于aj的点,比较一次;
外部循环条件为i<j
AC~~~~~~~~~~~~~~~~(⊙o⊙)
public class No11_ContainerWithMostWater {
public static void main(String[] args){
System.out.println(maxArea(new int[]{1,2}));
}
public static int maxArea(int[] height){
int i = 0, j = height.length-1;
int start = height[i];
int end = height[j];
int max = (start<end?start:end)*(j-i);
while(i<j){
if(height[i] <= height[j]){
while(height[i] <= start && i<j) i++;
if(height[i] > start)
start = height[i];
}
else{
while(height[j] <= end && i<j) j--;
if(height[j] > end)
end = height[j];
}
if(max < (start<end?start:end)*(j-i))
max = (start<end?start:end)*(j-i);
}
return max;
}
}