11. Container With Most Water
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.
大概意思就是给你个数组,下标代表x坐标,数组元素代表相应的y坐标值。
从y坐标向x轴引垂线,求两条垂线,使得他们围成的容器装水最多。
双层for循环那种暴力解法肯定不会满足时间要求。所以尽量选择时间复杂度为O(n)的解法。
解题思路:首尾两个指针分别往中间移动,由于求装水最多,所以求area时,
只考虑对比的两条垂线中最短的那条就可以,每次都记录相应的area。
最后返回最大的area即可。首先想到了下面的第一个方法,但是这个方法还是超过了时间限制。如下:
public class Solution {
public int maxArea(int[] height) {
if (height.length<2) {
return 0;
}
int start = 0;
int end = height.length-1;
int area = 0;
while (start < end) {
int v = Math.min(height[start], height[end])*(end-start);
area =Math.max(area,v);
if (height[start]<height[end]) {
start++;
}else {
end--;
}
}
return area;
}
}
然后,仔细考虑,发现,其实在移动的时候,以start为例,
当移动start时,它右边的值如果比start所在位置的元素小的时候,可以不用计算了,
因为它不会在比start位置的元素求的area大。
end方向同理。继续优化上面的方法得到下面的代码:
public class Solution {
public int maxArea(int[] height) {
if (height.length<2) {
return 0;
}
int start = 0;
int end = height.length-1;
int area = 0;
while (start < end) {
int v = Math.min(height[start], height[end])*(end-start);
area =Math.max(area,v);
if (height[start]<height[end]) {
int k = start;
while (k < end && height[k]<=height[start]) {//只要start右边的元素比start所在位置的元素小
k++; //就可以不用在算面积,因为不会比start所在位置的元素求出的面积大
}
start = k;
}else {
int k = end;
while (k > start && height[k]<=height[end]) {//只要end左边的元素比end所在位置的元素小
k--; //就可以不用在算面积,因为不会比end所在位置的元素求出的面积大
}
end=k;
}
}
return area;
}
}