给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
垂直的两条线段将会与坐标轴构成一个矩形区域,较短线段的长度将会作为矩形区域的宽度,两线间距将会作为矩形区域的长度,而我们必须最大化该矩形区域的面积。这里笔者使用了两种方法-暴力破解法/双指针法
暴力破解法:
遍历两遍数组,第一遍i是容器左端,第二遍从i后面开始的j确定容器右端,容量就是min(height[i],height[j])*(i-j),设定一个max每次与其进行比较存放最大容量即可,很好实现,但这种办法时间复杂度太高O(n2):
参考代码:
int maxArea(int* height, int heightSize) {
int tall = 0,len = 0,max = 0;
for(int i =0;i<heightSize;i++){
for(int j =i+1;j<heightSize;j++){
tall = height[i]<height[j]?height[i]:height[j];
len = j-i;
int capacity = tall*len;
max = max>capacity?max:capacity;
}
}
return max;
}
双指针法:
这个方法使用两个指针,分别位于头尾,两端中最小(短)的那个,我们可以视之为拖后腿的,为了不拖后腿获以得最大面积,它将要向内侧移动去寻找变大的可能,即使向内侧靠拢会减小长度,但若能变得更大(高),我们将能够弥补这个损失,每移动一步,进行一次判断,直至两个指针相遇;在这个过程中,和之前方法一样,用max记录下最大容量值,此时因为只遍历了一边数组,所以时间复杂度大幅降低为O(n):
参考代码:
int maxArea(int* height, int heightSize) {
int left = 0,right = heightSize-1,max =0,capacity,tall;
while(left<right){
tall = height[left]<height[right]? height[left]:height[right];
capacity = tall*(right-left);
max = max>capacity?max:capacity;
if(tall==height[left]){
left++;
}else{
right--;
}
}
return max;
}