盛最多水的容器|刷题打卡

186 阅读2分钟

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

说明:你不能倾斜容器。

示例 1 image.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

示例 3:

输入:height = [4,3,2,1,4]
输出:16

示例 4:

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

解题思路

这道题不妨带入到一个真实的生活场景中:把整个数组想象成一个大箱子,把每个端想成一个木板,假设每次只知道头尾两个板的情况,并且可以知道当时盛水的容量。允许你每次测量完后,向内换掉一块板子,你会换哪一块呢?

答案当然是换掉当时头尾两个板中较短的一块。因为把长的换掉,注定能盛的水只能越来越少。在每一步上,我们尝试换掉短的板子,看看是不是能盛更多的水。

这样我们的答案就呼之欲出了:

  1. 每次选定头尾两个板,计算当时的盛水量
  2. 将此时的盛水量和之前的盛水量比较,取更大的一个
  3. 比较头尾两个板哪个更短,将这个板向内更换一个
  4. 回到步骤1,直到所有的木板都尝试过了。

代码如下:

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
  const width = height.length;
  let head = 0;
  let tail = width - 1;
  let value = 0;

  while(head < tail) {
    const left = height[head];   //左边木板的高度
    const right = height[tail];  //右边木板的高度
    const area = Math.min(left, right) * (tail - head); //目前的盛水量
    value = Math.max(value, area);
    if(left<right) {
      head++
    } else {
      tail--;
    }
  }

  return value;
};

总结

这道题其实是一个贪心算法。即在不知道总体的情况下,每一步尽量取求取最大的值,以期望最后求出总体最大的值。在具体代码上,采用了双指针代表头和尾两个端点。一次遍历就可以找出最大的可能性。

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情