给定一个长度为
n
的整数数组height
。有n
条垂线,第i
条线的两个端点是(i, 0)
和(i, height[i])
。找出其中的两条线,使得它们与
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提示:
n == height.length
2 <= n <= 105
0 <= height[i] <= 104
时间复杂度:O(N),双指针遍历一次底边宽度 N 。
空间复杂度:O(1),指针使用常数额外空间。
思路:
双指针法:
1.设置双指针 i, j 分别位于容器壁两端,根据规则移动指针(后续说明),并且更新面积最大值 res
,直到 i == j
(i和j相遇)时返回 res
。
2.规则:当 i 和 j 两端某一端较短时,取较短的那一端使其向中间方向移动,目的是尽可能找到能使其更高的值(矮->高),这样就有可能使面积area变得更大。
总结:宽度变短的情况下,尽可能使较矮的一端变得更高,这样才能使面积尽可能的大。
C++版本示例:
int maxArea(vector<int>& height) {
// 双指针法:高度按i和j指向两端,宽度不断减小,计算面积
int i = 0;
int j = height.size() - 1; // 下标从0开始
int maxArea = 0; // 特殊情况下:当输入为[0, 2]时,面积应为0,所以不能初始化为1
while (i < j)
{
int area = (j - i) * min(height[i], height[j]); // 宽(不断缩小) * 高(最小)
maxArea = max(area, maxArea);
if (height[i] <= height[j])
i++; // 固定长的柱子(j),然后让短的柱子(i)试着右移使其高度变大,从而使得面积area变大
else
j--; // 固定长的柱子(i),然后让短的柱子(j)试着左移使其高度变大,从而使得面积area变大
}
return maxArea;
}
Go版本示例:
// i和j中较短的一边向中间靠拢,直至两者相遇
func maxArea(height []int) int {
res := 0
for i, j := 0, len(height) - 1; i <= j; {
// 1.计算最小高度(容纳最多的水取决于容器两边的最小高度)
// 2.计算当前面积,并更新最大面积
area := (j - i) * min(height[i], height[j])
res = max(res, area)
// 两边不断向中间靠拢(宽度减小),所以面积增加的唯一途径就是增加两边中较小一边的最大高度
if height[i] < height[j] {
i++
} else {
j--
}
}
return res
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a < b {
return b
}
return a
}