011-盛最多水的容器-力扣
一:题目描述
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
例如:
二:解决思路以及代码
(一):暴力算法
作为一名资深菜鸡,这道题想到的第一种解决方法自然是暴力算法
代码如下:
public static int maxArea(int[] height){
int area = 0; //用来存储最大容量值
//双层循环
for (int i = 0; i < height.length; i++) {
for (int j = i+1;j<height.length;j++){
int lenght = 0;
if (height[i]<height[j]){
lenght = height[i];
}else {
lenght = height[j];
}
int area_temp = (j-i)*lenght;
if (area < area_temp){
area = area_temp;
}
}
}
return area;
}
循环嵌套解千愁,唯独解不了时间超时(手动狗头)
(二):双指针
使用循环嵌套确实爽,但是时间超时确实很下头,那么来寻找另外的解决办法吧
这道题我们还可以使用双指针的思想来解决,
- 开始定义两个指针i,j分别指向数组第一个数据和最后一个数据
- 然后使这两个指针指向的数据中最小的那个值与指针之间的距离相乘:如i指向值最小,则area = height[i]*(j-i)
- 然后判断得到的面积是否比上一轮得到的面积大,如果大,则替换,否则不执行
- 接着让两指针指向数据较小的指针移动,如i指向的值较小,则让i加一,j不动。又如j指向的值较小,则让j减一,i不动
- 直到i与 j指针相遇,循环结束
该算法的时间复杂度为:O(n)
举例:
初始化指向数组定义两个指针指向数组的开头和结尾两个数据
此时可容纳的水量为min(1,7)*8 = 8。由于左指针对应的数字较小,我们移动左指针:
同理上述操作,直到两个指针相遇,结束程序
两个指针为什么要移动较小值的那个指针呢?
我的理解如下:当前两个指针分别指向两个数据,那么此时的面积为area_1 = min(height[i],height[j])*(j-i),我们假设指针 i 指向的值比指针 j 指向的值要小,那么此时的area_1的值与 height[i]有关,而与height[j]无关,那么此时让指针 i 移动,得到面积area_2,可能会比area_1大,也可能比area_1小,但是不让 i 移动,而是让 j 移动,那么此时无论height[j]>height[i] 还是height[j]<height[i],得到的面积area_2,都一定满足:area_2<=area_1,那么这种情况就把问题转变成了寻找容量最小的容器了,没有意义。
总结一下:移动值较小的那个指针得到的面积可能变大,也可能变小,但是移动值较大的那个指针得到的面积一定会变小,所以移动值较小的那个指针。
代码
public static int maxArea_point(int[] height){
int i = 0,j = height.length-1;
int temp=0, max = 0;
while (i<j){
if (height[i]>=height[j]){
temp = height[j]*(j-i);
if (max<temp){
max = temp;
}
j--;
}else {
temp = height[i]*(j-i);
if (max<temp){
max = temp;
}
i++;
}
}
return max;
}
题目来源:盛最多水的容器