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.
==========
Analysis:
The most strait forward approach is calculating all the possible areas and keep the max one as the result. This approach needs O(n*n) time complexity, which could not pass OJ (Time limit exceed).
public class Solution {
public int maxArea(int[] height) {
if (height.length<2) return 0;
int max = 0;
int area = 0;
for(int i=0; i<height.length-1; i++){
for(int j=i+1; j<height.length; j++){
area= (j-i)*Math.min(height[i],height[j]);
max = Math.max(max, area);
}
}
return max;
}
}
In order to solve the problem in O(n), my initial idea was trying to keep one factor in the area function be the max value. I firstly tried keeping the maximum high, but then found that the height of the area was determined by the shorter line. As I could not keep both line maximum, I started to focus on the maximum length of area. In this case, I need 2 pointers initially point to the start and the end of the array, and my thought stopped at this point.
After reviewing the available solution in Internet, there is so called "closing into the centre" approach. Idea of which is set two pointer at the start and end of the array (which I has thought about that), then move the shorter pointer each iteration. The idea be hide this movement is that if we move the longer line, no matter how many steps we move, the new area would be smaller than the one before movement. This is because area = (end-start)*min(height[start], height[end]) <- after move, (end-start) decrease, min(height[start], height[end]) remains no change, still the "shorter line".
public class Solution {
public int maxArea(int[] height) {
if (height.length<2) return 0;
int start = 0;
int end = height.length-1;
int max = 0; // result
while(end>start){
int area = (end-start)*Math.min(height[end], height[start]);
max = Math.max(max, area);
if(height[end]<height[start]) end-=1;
else start+=1;
}
return max;
}
}
Remark: O(n).