leetcode盛最多水的容器-最大容器问题如下
问题分析:此题就是,有哪两条边围成的容器,可以盛更多的水。这里的边即是上图中的每根柱子,也就是数组中元素对应的值,所以容器的高取决于较低的那个柱子,因为水若没过会从上流出,容器的宽度取决于两根柱子之间的长度。
故问题可简化为求数组中 Min(a[i],a[j]) × | i-j | 的最大值; a[i],a[j]为上图中i,j任意两点的对应的柱子;
解决思路: 我们可以看到上诉图或者公式中,容器的高度取决于较低的那个柱子,当我们选择一个最低的柱子i = 0时,其他任何柱子都比其高,所以容器的高度即是a[0]它本身的高度值,它要想组成一个最大的容器,必须找它最远距离的柱子,也就是最后一个;
我们继续观察第二低的柱子,也就是第4根,对于它来说,除了第一根柱子,其他柱子都比它高,所以高度值又是一定的,所以要想组成最大容器,还是找最远的柱子即可,第一根不必再考虑,因为它与第一根所围成的容器已包含在第一根考虑的情况中,一定小于或等于第一根最大情况的值。
这样剩余的每一根柱子,只用考虑比自己不比自己低的柱子中,哪个距离自己最远即可,这可以称为该柱子的最优辅柱 (‘’辅柱‘’是我自己瞎起的,意思就是只帮着自己完成另一边的盛水工作,还不坑自己,不会漏水)
最后,其实只需遍历一遍,找到每根柱子的“最优辅柱”即可,算一下哪根柱子跟自己的“最优辅柱”配合得好,盛的水最多。
算法实现: 然而如何找到每一根柱子的“最优辅助”呢?寻找最远不比自己低的柱子,最快的方法就是从两头开始,也就是数组的头部和尾部,因为两头距离最长;
当第一根柱子与最后一根柱子相遇时,最后一根柱子比第一根要高,所以它可以被称为第一根柱子的“辅柱”,并且它还距离第一根柱子最远,故它是第一根柱子的“最优辅柱”,第一根柱子找到了最优辅柱就不用在考虑第一根柱子了;
然后再移到第二根,它与最后一根相遇时,判断一下谁是谁的“辅柱”呢?没错,第二根比最后一根高,所以它是最后一根柱子的“最优辅柱”,然后继续比较倒数第二根;
这样只要从两头开始,两根柱子相遇,它们其中一根必是另一根的“最优辅柱”,然后两头依次往中间移动,最后当所有的柱子都被遍历完后,除了最高的柱子,每根柱子都会有其“最优辅柱”,最高的柱子可能是多个柱子的“最优辅柱”,而且可能因为自身太高,太强,没有与其对应的辅柱(谁和其搭配都会漏水),不过它的最优情况已包含在之前的柱子中,所以不必考虑。
最后将所有的“最优辅柱”所搭配的值相比较,即可得到最优的解,这些可以在移动过程中进行比较
以上柱子两头移动比较的方法,也是双指针算法的一种,两头为两个指针,逐步比较,然后向中心移动。
Java实现方法:
import java.util.Random;
public class findTheMax {
public static void main(String[] args){
Integer[] testArrays = getArray(5);
FindThemax(testArrays);
}
static Integer[] getArray(int n){ //此函数为生成并返回一个随机数数组(可忽略),n为数组大小
Random r = new Random(521);
Integer[] Arrays = new Integer[n];
for(int i=0;i<n;i++){
Arrays[i] = r.nextInt(100);
System.out.print(Arrays[i]+",");
}
System.out.println("");
return Arrays;
}
static void FindThemax(Integer[] arrays){ //该问题寻找最大解的主函数
int i = 0,j = arrays.length-1; //放置两头指针
int theMax = 0;
while(i<j){ //判断指针是否到中心相遇
if(arrays[i]<arrays[j]){ //对两根柱子高度进行比较
theMax = Math.max(theMax, arrays[i] * (j - i)); //选择头部柱子的“最优辅柱”解,比较与之前已算柱子解的最大值
i++; //向后一根柱子移动
}else {
theMax = Math.max(theMax, arrays[j] * (j - i)); //选择尾部柱子的“最优辅柱”解,比较与之前已算柱子解的最大值
j--; //向后一根柱子移动
}
}
System.out.println("The max value is "+theMax); //输出最大解;
}
}
FindThemax函数中,while循环只将该数组遍历了一遍,进行比较操作,所以该程序的时间复杂度为O(n);
总结: 该问题是一个双指针算法问题,通过普通方法,进行两层for循环遍历所有数组元素,将每一个柱子一一相结合计算容器大小也可以实现,但是会有计算冗余,因为其中有一部分不必再计算,可以省略,就是当Min(a[i],a[j])固定为a[i]时,a[j]的大小不必考虑,i-j只需找到最远的即可,双指针就是简化省略了这部分的计算。