题目描述:
1、暴力双重循环
思路:首先拿到这道题我们需要找盛水最多的容器,看图很明显发现,这个盛水最多的容器无视了中间垂线的高度,只需要盛水,可以只看做我们只需要关注两条线,l 和 r,找到这两条线就可以计算出此时盛水的数量,Math.min(height(l),height(r))*(r - l);
我们只需要遍历数组height,外循环定义 l 这条线的位置,内循环定义 r 这条线的位置,再分别算出各个位置的盛水数量就可。
来看看代码:
public int maxArea(int[] height) {
int maxArea = 0,temp = 0;
int min;
for (int l = 0; l < height.length-1; l++) {
//当上一条线大于当前线,则证明可以跳过本次循环
if ( temp >= height[l]) continue;
temp = height[l];
for (int r = l+1; r < height.length; r++) {
min = Math.min(temp,height[r]);
maxArea = Math.max(maxArea,min*(r-l));
}
}
return maxArea;
}
时间复杂度:由于是双重循环,所以为O(n^2)
空间复杂度:O(1)
2、引入双指针
思路:第一种方法我们是固定 l 的位置,移动 r 的位置,来得到每一个位置的盛水数量再比较,我们不难看出这种方法十分耗费时间,双重循环,也会算出很多重复值,所以我们会想能不能优化一下?
当然可以,我们可以引入两个指针变量,l 和 r,因为我们求盛水数量,关键点在于两条边界线,找出两者最小值Math.min(height(l),height(r))*(r - l),所以我们可以引入一个判断条件,当height(l)<height(r)时,证明当前位置盛水数量=height(l)*(r-l),再移动l指针,l++;反之当height(r)<height(l)时,证明当前位置盛水数量=height(r)*(r-l),再移动r指针,r--即可;这样我们就只需要遍历一轮,当l = r 证明,循环可以结束了。
看看代码:
public int maxArea(int[] height) {
int l = 0,maxArea = 0;
int r = height.length -1;
while (l < r){
maxArea = height[l] < height[r]
? Math.max(maxArea,(r-l)*height[l++])
: Math.max(maxArea,(r-l)*height[r--]);
}
return maxArea;
}
时间复杂度:只进行了一轮循环,故为O(n)
空间复杂度:O(1)
总结:这道题拿到手感觉有点类似leetcode第82.柱状图的最大矩形(大家感兴趣可以移步——柱状图的最大矩形),但是仔细看了会发现,其实不然,主要就是因为这道题没有考虑实际情况,忽略了中间的垂线,所以就简单很多,但还是值得一写的。