LeetCode数组篇(六):盛最多水的容器

题目:盛最多水的容器

给你 n 个非负整数 a1,a2,…,an,每个数代表座标中的一个点 (i, ai) 。在座标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

示意图

图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例:

输入:[1,8,6,2,5,4,8,3,7]
输出:49

道人第一想法就是暴力求解

这里道人说明下,暴力求解并没什么不好;道人解释下原因和自己的理解。

  • 首先:计算机就是做运算的,就是擅长做重复的逻辑计算,以现在计算机的性能,一些在你眼中的高时间复杂度的工作,也许效率并不是你想象的那么低。
  • 如果说第一个原因你说有些牵强,那么下面两个原因,也许能为暴力求解找出合理的解释。
    • 数据量不大:在业务场景(数据量不大)的情况下,O(n)与O(n二次方)的差距并不大。
    • 代码可读性强:相对而言,暴力求解算是很容易被不同的人理解的。
    • 方便理清逻辑:暴力求解,其实是帮我们理清最基础的逻辑,在理清基础逻辑后,如何优化?如何转换角度?如何提高性能?暴力求解都给我们奠定了优化该题的基础。

暴力求解:任意两点(ai,aj)的容器容积的计算公式Math.min(ai,aj)*(j-i)。

代码如下

class Solution {
    public int maxArea(int[] height) {
        // 暴力求解
        int maxArea = 0;
        for (int i = 0; i < height.length; i++){
            for(int j = i+1; j < height.length; j++){
                if (Math.min(height[i],height[j])*(j-i) > maxArea){
                    maxArea = Math.min(height[i],height[j])*(j-i);
                }
            }
        }
        return maxArea;
    }
}

第二思路: 双向指针(排除了很多明显小于当前容积的情况)

核心:选取最左、最右两个指针,实际上是获取了以较小高度为一边的所有容器的最大容积!!!!剔除了中间的很多明显小于当前容积的情况!!!

从头到尾遍历必须再次嵌套一层循环,那么从尾到头遍历啦?或者双向指针一起遍历?会是什么结果。

分析思路:

  • 不难发现暴力求解存在着大量的重复计算。
    以i=0该点为例,假若height[i]为较低的一点,那么高度则以height[i]为基准,最大容积与长度相关则height[height.length-1]为构成的最大容积(以i=0该点为一边的容积)。
  • 若我们以height左右两边为起点,以两边较小值为一边,便是此时最大容积;**那么怎么移动才可能使下一个容积大于当前容积?**较大一边的指针向中间移动?由于底边减少,那么容积要想大于原来的值,高度必须大于原高度,那么由于移动的较大一边的指针,所以此时高度由原来的较小高度一边限制,因此不可能大于原容积。
  • 所以,移动两边中较小高度一边的指针,才有可能在接下来的比较中获取到比原来更大的容积。

上述逻辑的演示:(记住一点只有较小高度一边的指针移动,新的容器值才可能大于上一个容器值;同时你每次获取的均是以较小边为容器一边的最大值)

代码如下:

class Solution {
    public int maxArea(int[] height) {
        // 双指针求解法
        int maxArea = 0;
        int i = 0;
        int j = height.length-1;
        while( j > i){
            // 计算当前的最大容器值
            maxArea = Math.max(Math.min(height[j],height[i])*(j-i),maxArea);
            // 较小一边的指针移动
            if (height[j] > height[i]){
                i++;
            } else {
                j--;
            }
        }
        return maxArea;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章