Leetcode 11 :盛最多水的容器 - 双指针

142 阅读2分钟

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

说明:你不能倾斜容器。

示例 1:

img

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

题解:

这题刚拿到手的时候也是一脸懵逼,瞟了一下题解

看到双指针的时候稍微有一点底。

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    var left = 0;//初始化左边的指针 指向数组的第一个
    var right = height.length-1;//初始化右边的指针 指向数组的最后一个
    var area = 0;//初始化面积为零
    //当两个指针相遇 整个过程结束
    while(left != right){
        //h为水的高度,数值小的就是当前的高度
        var h = height[left]<height[right]?height[left]:height[right];
        //运算当前的面积,并与之前的面积进行比较,最后取大的那个
        area = h*(right-left)>area?h*(right-left):area;
        //移动指针
        if(height[left]>height[right]){
            right = right - 1;
        }else{
            left = left + 1;
        } 
    }
    return area;
};

这题的主要难点我认为有两个,一个是跳出循环的条件(可能是我蠢,我想了好久),还有一个是每次判断完area以后要怎么变换指针。

任何的算法题都不是一步到位的,我们拿到算法的第一步就是想到什么就写什么。比如我最开始就声明两个指针,并把它们初始化。然后我声明了一个h变量,这个用来记录当前的水高度,并且用双目运算符写了表达式。接着写area的表达式。

到这里我所有第一时间能想到的都写完了。

再就是该怎么控制循环结束和移动指针。

移动指针有两种情况:

  • height[left]>height[right]
  • height[left]<height[right]

这时候肯定是用if和else来控制

那到底怎么移动呢?

这时就是贪心法的思维了

因为我们的指针是从最两边开始的,所以在最初的情况下,我们保证了宽度最大,那么接下来只要保证高度就好了,所以每一次移动的时候要尽量保留数值大的那个。

于是就有了:

 if(height[left]>height[right]){
            right = right - 1;
        }else{
            left = left + 1;
        } 
    }

那么写到这里差不多就能知道循环条件了,整个过程在不停变换的就是我们的两个指针,所以循环跳出的条件就是!他们相遇了!

—完结撒花—