给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
示例 1
输入:[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,直到所有的木板都尝试过了。
代码如下:
/**
* @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 春招闯关活动」, 点击查看 活动详情