题目
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water
先讲一下我自己的暴力把,毕竟脑壳瓜子没 有灵光一闪的时候。
暴力求解思路:
首先坐标(i,ai),其中i表示数组中索引,ai表示索引对应的值
i和j分别代表两个索引位置,j-i为第一条线,height[i]或height[j]为第二条线
其中,当height[i]>height[j]时,第二条线为height[j],否则为height[i],这是因为
第二条线只能取两个值中小的那一个(木桶原理:水只能装到板最短的那块)。
算法步骤
1.input : int [] height, int i=0, int j=i+1,int tempArea=0, int area;
2.output : area;
3.tempArea=min(height[i], height[j])*(j-i),判断tempArea是否大于area,如果是,转至4,否则,转至5;
4.area=tempArea, j=j+1, 如果j5.j=j+1,如果j 6. i=i+1, j=i+1, 转至3; 如果i=height.length-2, 转至7;
7. return area.
写完了渣渣算法,那就来实现一下。
public int maxArea(int[] height) {
int area=0;
for(int i=0;i<height.length;i++){
for(int j=i+1;j<height.length;j++){
if(height[i]<height[j]){
int temp=height[i]*(j-i); //暂存计算结果
area=(area<temp)?temp:area;
}else if(height[i]>height[j]){
int temp=height[j]*(j-i);
area=(area<temp)?temp:area;
}else{
int temp=height[i]*(j-i);
area=(area<temp)?temp:area;
}
}
}
return area;
}
运行时间是1042ms,空间复杂度是O(n^2)。
看到这么菜的实现,我肯定是忍不了的,那肯定有好办法去解决它,虽然现在不能一次性想到,但是在通往一次性想到的路上。
下面是参考leetcode官方解答思路,正正宗宗的双指针。
首先令first=0, last=height.lenght-1;头指针放在数组的第一个位置,尾指针放在数组的最后一个位置。然后,计算两个位置的容器面积area,然后移动较小元素的指针(这里同样是木桶原理,装水只能装到最短的那块板),计算移动后的指针面积,比较两次面积大小,取最大的。当first和last指向同一个位置时,返回area。
本着知其然知其所以然的道理,我把它写成算法
- input : int[]height , int first=0, int last=height.length-1, int area;
- output: area;
- 判断last>first,为真,转至4,否则转至7;
- 计算int tempArea=min(height[first],height[last])*(last-first),area=max(tempArea,area);判断height[first]>height[last],为真,转至5,否则转至6;
5.last=last-1,转至3;- first=first+1,转至3;
- return area;
根据这个算法,java实现如下:
public int maxArea(int[] height) {
int first=0;
int last=height.length-1;
int area=0;
while(first<last){
if(height[first]<=height[last]){
int temp=height[first]*(last-first);
area = (area<temp)?temp:area;
first++;
} else {
int temp=height[last]*(last-first);
area=(area<temp)?temp:area;
last--;
}
}
return area;
}
运行时间3ms,时间复杂度O(n),哇,what can i say? do it!!
这里还有一个问题,那就是得证明这个方法求出的一定是最大值
给大家指一条明路:
https://leetcode-cn.com/problems/container-with-most-water/solution/sheng-zui-duo-shui-de-rong-qi-by-leetcode-solution/