「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
题目:给定一个n个非负数,利用此n个非负数在坐标内画垂线,横坐标依次累加,纵坐标即为n个非负数,求这些垂线和x轴构成的容器最大面积。
暴力解法
首先想到的是暴力解法,只需要找到所有可能的面积值就可以,方法就是双重for循环遍历,时间代价显而易见,有点担心过不了测试,代码如下:
public static int maxArea(int[] height){
int maxArea = 0;
for(int i=0;i<height.length-1;i++){
for(int j=i+1;j<height.length;j++){
maxArea = Math.max(maxArea, Math.min(height[i], height[j])*(j-i));
}
}
return maxArea;
}
上述算法时间复杂度,空间复杂度为,LeetCode官方测试结果为超出时间限制。
双指针法
其实容器最大面积组成有两个:
- 左右两边的垂线越远越好。
- 垂线的高度越高越好,但面积取决于短的那条。
对于第一点,我们只需要初始设置两个指针,一个指针指向数组的首索引位置,另一个指向数组的尾索引位置,这样就能保证左右两边的垂线距离为最大。对于第二点,垂线的高度来自数组,面积取决于较短的那个垂线,此时只需要记录当前的面积然后比较左右两个指针指向的索引对应的元素的值,哪个值比较小就移动指针,尝试寻找最大的面积,将每次的面积记录下来与最大面积比较即可。代码如下:
public static int maxArea2(int[] height){
int left = 0, right = height.length-1;
int maxArea = 0;
while (left<right){
maxArea = Math.max(maxArea, Math.min(height[left], height[right])*(right-left));
if(height[left]<height[right]){
left++;
}else {
right--;
}
}
return maxArea;
}
此方法两个指针最大的移动距离为数组的长度,因此算法的时间复杂度为,在算法中也只用到了常数量的参数,因此算法的空间复杂度为。测试结果:
总结
双指针法的应用很多,如非常典型的快慢指针,可以通过快慢指针来判断一个单链表是否存在环,关于双指针,更多的总结可以看这里:算法 | 双指针套路总结。