手摸手提桶跑路——LeetCode11. 盛最多水的容器

164 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第32天,点击查看活动详情

题目描述

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

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

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

说明:你不能倾斜容器。

示例 1:

捕获.PNG

输入:[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

解题思路——暴力求解

这不是普通的暴力求解,这是王维诗里的暴力求解,手动狗头/.

一开始是没有想用暴力的,顶级前端怎么能用暴力草草了事呢?于是我左思右想辗转反侧,然而脑力里的暴力求解法挥之不去,仿佛不用暴力解一遍我就不会似的(可不就是呢)。

没有办法,只好妥协。

这道题就是求面积,两根板之间可乘水量的最大面积。根据短板理论,一只木桶盛水的多少,并不取决于桶壁上最高的那块木块,而恰恰取决于桶壁上最短的那块。好耶,这不信手拈来了?

只要用 双层循环 两两将木板的面积求出来,最后得出最大的面积,不就完事了。

噼里啪啦,提交,超时,很快啊,心凉了半截,在这个炎热的夏天里格外的特别。

跑路是不可能跑路的,也不会别的解法了,超时了就得想办法优化,既然盛水多久取决于短板,那如果我的左边板 height[left] * height.length 比当前最大面积还小的话,内层循环就直接跳过了。

题解

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    const lens = height.length;
    let max = 0;
    for(let i=0; i<lens; ++i) {
        if(height[i] * (lens - 1) < max) continue;
        for(let j=i+1; j<lens; ++j) {
            max = Math.max(Math.min(height[i], height[j]) * (j - i), max);
        }
    }
    return max;
};

捕获.PNG

解题思路——双指针

先看图: 盛水最多的容器.gif 还是基于短板理论:木桶可盛的最大水量是基于最短的那条板。

捕获.PNG

拿这个阶段来讲解一下,ir 这两块中,短板为 i,如果能够移动这两个板中的其中一块,使得新的面积 有可能 大于当前 ij 组成的最大面积 S(i, j),那么移动谁的可能性更大?

微信图片_20201208110801.jpg

假设法走一走。假设我们移动的是最高的板 j,那么下一个板 j - 1 的高度 可能大于板i,那么此时最短板高度为依然是 height[i],根据短板理论,意味着面积依然是由 height[i] 决定的;如果下一个板 j - 1 的高度小于板 i,那么最短板的高度为 height[j - 1],组成的面积比不移 height[j]更小了。也就是说,如果移动最高的板,那么结果只能是 移动后的面积 S2 <= 移动前的面积 S1

微信图片_20220824182841.jpg

如果移动的是最短的板呢,那么 height[i + 1] 的高度可能高于 height[i],如果高于 height[i] 的话,那么 移动后的面积 S2 > 移动前的面积 S1;如果小于 height[i] 的话,那么 移动后的面积 S2 < 移动前的面积 S1

那么题目要求我们找到最大盛水的板子,如果搁这移最长的板子,你寻思寻思你能找到啥?

微信图片_20220727220717.jpg

题解

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    const lens = height.length;
    let l = 0, r = lens - 1, max = 0;

    while(l < r) {
        max = height[l] > height[r] ? 
            Math.max((r - l) * height[r--], max) 
            : Math.max((r - l) * height[l++], max);
    }
    return max;
};

捕获.PNG