给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。
找出其中的两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例 1:
输入:[1,8,6,2,5,4,8,3,7] 输出:49 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1] 输出:1
提示:
-
n == height.length
-
2 <= n <= 10^5
-
0 <= height[i] <= 10^4
思路:
对数组进行放缩法,按照某种规则从左向右缩,或者从右往左缩
缩放规则按照左边的右边与右边的左边进行比较,指针指向较大的。比如h[0]与h[8],先计算两者围成的容积,在比较h[1]和h[7]哪一个比较大如上图则左指针指向h[1]。
//IDEA 测试版本
public static void main(String[] args) {
int[] h = {1,8,6,2,5,4,8,3,7};
System.out.println(maxArea(h));
}
public static int maxArea(int[] height){
int[] h = height;
int end = height.length - 1;//用来指向数组的最后元素
int begin = 0;//用来指向数组的第一个元素
int max = 0;//用来储存最大值
//进行放缩
while(end != begin){
//(end - begin) * Math.min(h[end], h[begin])为本次的容积
max = Math.max((end - begin) * Math.min(h[end], h[begin]),max);
if(h[begin + 1] >= h[end - 1]) begin++;
else end--;
}
return max;
}
存在一些案例没有通过,应该是指针移动过程当中存在问题,试想是不是应该那个指针小就移动哪一个,于是修改了一下代码
public static int maxArea(int[] height){
int[] h = height;
int end = height.length - 1;//用来指向数组的最后元素
int begin = 0;//用来指向数组的第一个元素
int max = 0;//用来储存最大值
//进行放缩
while(end != begin){
//(end - begin) * Math.min(h[end], h[begin])为本次的容积
max = Math.max((end - begin) * Math.min(h[end], h[begin]),max);
if(h[begin]<=h[end]) begin++;
else end--;
}
return max;
}
这就产生了一个思考,为什么只移动小的指针就能够保证肯定留下了最大的容积呢?
原因是这样的当前左指针和右指针指向的数分别为 x 和 y,不失一般性,我们假设 x≤y。同时,两个指针之间的距离为 t。那么,它们组成的容器的容量为:
min(x,y)∗t=x∗t
假如X为两者里面较小的,我们不移动x而移动y,那么无论我们怎么移动其结果也不会超过x*t,因为我们要取最小值,所以选取的值只会≤x。因此指针必须要从小的开始移动。