7.盛最多水的容器
题目描述
给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。
找出其中的两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
思路:
最开始的做法,用双指针,左指针:若当前start大于左指针位置数值,必然不可能选它(当前start远且大),若小于则比较,以当前end为右挡板,判断start为左挡板和左指针为左挡板谁面积更大。右指针与其类似。但是这种做法只能适合部分场景,比如start当前停在了一个比右指针小很多的挡板,右指针即使值很大,也可能被跳过,但是实际上左指针还没有到的地方有比右指针值还大的挡板,例如
{1,1,1,1,1,100,99,1}
然后开始尝试暴力破解,以每根挡板为较短的那根,然后寻找所有比他大的挡板求面积进行比较,但是这种直接暴力破解会超时
后又对上面的暴力破解做优化,对每一根挡板,分别从0和length-1开始寻找比他大的挡板,找到后即可退出循环,因为我们最后选定的一定是距离他更远的那根挡板。
题解提供的思路:
双指针,一左一右,指针要移动必然造成宽度减小,那么现有较短的边如果保留必然使得面积变小,所以可以舍弃,但是较常边保留有可能使得面积变大,所以每次移动的指针是较短边的那边。
代码:
public static int maxArea2(int[] height){
if(height.length<=1)return 0;
//记录以每个挡板为较低板得最大area
int area = 0;
for (int i = 0; i < height.length; i++) {
//int tmp = 0;
// for(int j = 0;j < height.length;j++){
// if(i==j||height[i] > height[j])continue;
// tmp = Math.max(height[i]*(Math.abs(j-i)),tmp);
// }
//找到距离它最远的大于等于他的木板
int l = 0;
int r = height.length;
boolean flag1 = false;
boolean flag2 = false;
for (int j = 0; j < i; j++) {
if(height[j]>=height[i]){
l = j;
flag1 = true;
break;
}
}
for (int k = height.length-1; k > i ; k--) {
if(height[k] >= height[i]){
r = k;
flag2 = true;
break;
}
}
if(flag1&&flag2){
area = Math.max(Math.max(i-l,r-i)* height[i],area);
}else if(flag1&&(!flag2)){
area = Math.max((i-l)* height[i],area);
}else if(!flag1&&flag2){
area = Math.max((r-i)* height[i],area);
}
//area = Math.max(tmp,area);
}
return area;
}
参考题解后代码
public static int maxArea3(int[] height){
int l = 0;
int r = height.length-1;
int res = 0;
while(l<r){
res = Math.max(Math.min(height[l],height[r])*(r - l),res);
if(height[l]<=height[r])l++;
else r--;
}
return res;
}