11. 盛最多水的容器
题目描述
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
解题思路
思路一: 双指针
矩形的面积与两个因素有关:
- 矩形的长度:两条垂直线的距离
- 矩形的宽度:两条垂直线其中较短一条的长度
因此,要矩形面积最大化,两条垂直线的距离越远越好,两条垂直线的最短长度也要越长越好。
面积公式如下:
r
e
s
(
i
,
j
)
=
m
i
n
(
h
e
i
g
h
t
[
l
e
f
t
]
,
h
e
i
g
h
t
[
r
i
g
h
t
]
)
∗
(
r
i
g
h
t
−
l
e
f
t
)
res(i, j) = min(height[left], height[right]) * (right - left)
res(i,j)=min(height[left],height[right])∗(right−left)
我们设置两个指针 left 和 right,分别指向数组的最左端和最右端。此时,两条垂直线的距离是最远的,若要下一个矩形面积比当前面积来得大,必须要把 height[left] 和 height[right] 中较短的垂直线往中间移动,看看是否可以找到更长的垂直线。
算法流程:
初始化: 双指针 left , right 分别指向数组的最左端和最右端;
循环收窄: 直至双指针相遇时跳出;
更新面积最大值 res ;
较短的垂直线往中间移动;
返回值: 返回面积最大值 res 即可;
实现代码如下:
/**
* @param {number[]} height
* @return {number}
*/
var maxArea = function(height) {
let left = 0,
right = height.length - 1,
res = 0;
while(left < right) {
res = height[left] < height[right] ?
Math.max(res, (right - left) * height[left++]):
Math.max(res, (right - left) * height[right--]);
}
return res;
};
- 时间复杂度 O(n): 双指针总计最多遍历整个数组一次。
- 空间复杂度 O(1): 变量 left , right , res 使用常数额外空间。