【LeetCode】详解盛最多水的容器11. Container With Most Water Given n non-negative integers a1, a2, ..., an


前言

继续刷题,刷题一时爽,一直刷题一直爽。


正文

今天给大家带来的是一道求最大容积的问题

原题:

链接:盛最多水的容器

Given n non-negative integers a1, a2, …, an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
在这里插入图片描述
Example:
Input: [1,8,6,2,5,4,8,3,7]
Output: 49

题目大意
给定一个整数型数组,数组的元素就是容器的高度,比如数组[4, 5],表示容器左边高度为4,右边高度为5,其最大盛水量为4 * 1 = 4,即宽为1,高为4。这是因为盛水时看的不是最大高度,而是最小高度(短板效应),找出该容器的最大盛水量。

思路1:

最先想到的还是暴力遍历容器的高度,我们可以使用两层循环,暴力枚举出所有容器可能的盛水量,最后拿出最大的盛水量即可。

代码

public int maxArea(int[] height) {
    if (height == null || height.length < 2) {
        return 0;
    }
    int maxArea = 0;
    for (int left = 0; left < height.length; left++) {
        for (int right = left + 1; right < height.length; right++) {
            int currentArea = Math.min(height[left], height[right]) * (right - left);
            if (maxArea < currentArea) {
                maxArea = currentArea;
            }
        }
    }
    return maxArea;
}

代码讲解
代码中,使用left变量指向容器的左边,right指向容器的右边,left初始值为0,即指向容器最左边的高度,而right的初始值为left的下一个高度,即left + 1的高度;
currentArea是当前小容器下的盛水量,用Math.min(height[left], height[right])表示容器的高度(即短板),用(right - left)表示容器的宽度,盛水量 = 容器短板高度 * 容器宽度

如上图所示,当前盛水量为1,此时right右移,即right++
在这里插入图片描述
此时盛水量 = 1 * 2,right接着往下移,遍历出所有的盛水量,若当前容器盛水量大于maxArea则将maxArea的值进行更改。
从代码可以得出时间复杂度为O(N²),提交结果不会超时,但是挺慢的。
在这里插入图片描述

思路2:

由于在思路1中存在大量无效的判断,查找速度也比较慢,那么我们从减少无效判断的角度出发,我们可以将left固定在起点,right固定在终点,一开始容器的最大盛水量为整个数组的长度 * min(起点高度, 终点高度),如下图所示:
在这里插入图片描述
算出第一个盛水量后,我们需要移动哪个方向呢?建议读者先思考一下。
没错,我们要移动left,因为盛水量取决于短板高度,我们若想求得最大盛水量,则需要增大短板高度,此时left比right小,left需要增大,即left++。
我们通过不断改变left跟right的指向,得出最大盛水量。

代码

public int maxArea(int[] height) {
    if (height == null || height.length < 2) {
        return 0;
    }
    int maxArea = 0;
    int left = 0;                  //初始left的指向
    int right = height.length - 1; //初始right的指向
    while (left < right) {
        int currentArea = Math.min(height[left], height[right]) * (right - left);
        if (maxArea < currentArea) {
            maxArea = currentArea;
        }
        if (height[left] <= height[right]) {  //改变短板高度
            left++;
        } else {
            right--;
        }
    }
    return maxArea;
}

代码讲解
left的初始值为0,即指向容器的最左边,right的初始值为数组长度减1,即指向容器的最右边。
while循环中,只要left < right,即left跟right不碰面的情况下,就计算当前盛水量,并与maxArea进行比较,下面的代码块用来改变短板高度:

if (height[left] <= height[right]) {  //改变短板高度
    left++;
} else {
    right--;
}

若容器左边的高度小于等于容器右边的高度,则将左指针left++,指向下一个高度,同理若容器右边的高度小于容器左边的高度,则改变右短板,即right–,用图来解释一下吧,初始状态如下:
在这里插入图片描述
左边高度比右边小,所以下一次需要改变左边的短板,即left++,改变之后的状态如下:
在这里插入图片描述
移动依据:谁小移谁!,此时右小移右,改变右边短板,right–,移动之后如下图所示:
在这里插入图片描述
重复以上步骤,直到left跟right相遇
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如上图所示,由于left与right相遇,此时left比right小,left++,left等于right,不满足while(left < right)的条件,循环结束,返回最大结果,提交代码Success,速度还是明显提升了不少,舒服!
在这里插入图片描述


总结

若是有看了我上一篇博客的同学,会发现上一道题的思路3跟这道题的思路2有点类似,都是使用左右指针往中间夹,求出符合条件的结果。
上一篇博客:【LeetCode】详解三数之和
其实这是一种双指针类型的问题,思想都是差不多的,在LeetCode中也有专门的分类,感兴趣的同学可以自行查阅。
LeetCode双指针问题
好了,今天的题目讲解就到这里,如果有什么疑惑可以在下方留言中提出来,加油!

发布了57 篇原创文章 · 获赞 282 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/weixin_41463193/article/details/91942241