【前端也得会算法】11. 盛最多水的容器 [ 中等 ]

141 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

一、题目描述:

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

示例

示例 1: img

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

示例 2:

输入: height = [1,1]
输出: 1

提示:

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104

二、题解:

这道题意在取最大水量, 所以取最大水量得不断判断宽(差值)和高(相对最大)的积的最大值。

条件反射,这不就是双循环求值问题嘛,求出高小的那个和宽(序号差值)的积

所以要遍历数组,存储最大积就可

方法一 循环判断法

  • 原理。根据题解利用循环判断最大积即可。
  • 思路。
    • 利用双循环遍历
    • 取得i和j序号对应的数组最小高度值
    • 再Math.max取得最大积,高*宽最大

代码:

var maxArea = function(height) {
    let maxVal = 0
    for(let i = 0; i<height.length; i++){
        for(let j = i+1;j<height.length;j++){
             // 取得最小高度值
            let min = Math.min(height[i],height[j])
            // 取得最大积,高*宽最大
            maxVal = Math.max(maxVal, min*(j-i))
        }
    }
    return maxVal   
};

image.png

结果很尴尬,双循环超时了。

这个时候想起来使用while+双指针,这样肯定不会超时了。

优化后代码如下:

var maxArea = function(height) {
    let maxVal = 0
    let leftIndex = 0
    let rightIndex = height.length-1
    // 当左指针不小于右指针时跳出循环
    while(leftIndex<rightIndex){
        // 取得最小高度值
        let min = Math.min(height[leftIndex], height[rightIndex])
        // 取得最大积,高*宽最大
        maxVal = Math.max(maxVal, min * (rightIndex-leftIndex))
        // 最小值为右边的值时 右指针--
        if(min === height[rightIndex]){
            rightIndex--
            // 加这个是防止 左指针等于右指针序号对应的数组值,会使得左指针--,出错
            continue
        }
        // 最小值为左边的值时 左指针--
        if(min === height[leftIndex]){
            leftIndex++
        }
    }
    
    return maxVal   
};

image.png

三、总结

  • 此题可以循环判断法。暂时没有第二种方案
  • 循环判断法主要是根据题解利用循环判断最大积即可。

文中如有错误,欢迎在评论区指正