题目介绍
给定一个长度为
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
完整代码
public class Solution {
public int maxArea(int[] height) {
int l = 0, r = height.length - 1;
int ans = 0;
while (l < r) {
int area = Math.min(height[l], height[r]) * (r - l);
ans = Math.max(ans, area);
if (height[l] <= height[r]) {
++l;
}
else {
--r;
}
}
return ans;
}
}
思路详解
1. 初始化双指针
l
(left)指针初始化为数组的第一个元素,即最左边的线段。r
(right)指针初始化为数组的最后一个元素,即最右边的线段。
2. 循环计算面积
- 使用一个
while
循环,当l
小于r
时,循环继续。这确保了我们在计算面积时,总是考虑两条不同的线段。
3. 计算当前面积
- 在每次循环中,计算当前
l
和r
指向的两条线段所能围成的矩形面积。面积计算公式为:Math.min(height[l], height[r]) * (r - l)
。这里使用Math.min
函数是因为矩形的高度由较短的线段决定。
4. 更新最大面积
- 使用变量
ans
存储当前已知的最大面积。在每次循环中,将当前计算出的面积与ans
比较,并更新ans
为两者中的较大值。
5. 移动指针
- 根据当前
l
和r
指向的线段高度,决定移动哪个指针。如果height[l]
小于或等于height[r]
,则将l
指针向右移动(++l
),因为我们希望通过移动较短的线段来寻找可能更大的面积。反之,如果height[l]
大于height[r]
,则将r
指针向左移动(--r
)。
6. 返回结果
- 当
l
不再小于r
时,循环结束,此时ans
变量中存储的就是最大面积。返回ans
作为结果。
知识点精炼
1. 双指针技术
- 利用两个指针分别从数组的两端开始,向中间移动,以减少不必要的遍历,提高算法效率。
2. 贪心算法
- 在每一步选择中都采取当前状态下最优的选择,即移动较短的线段,以期找到可能的最大面积。
3. 面积计算
- 使用矩形面积公式:面积 = 底 × 高,其中底是两个线段之间的距离,高是两个线段中较短的那个。
4. 动态更新最大值
- 在遍历过程中,不断比较当前面积与已记录的最大面积,实时更新最大面积的值。
5. 循环条件
- 使用
while (l < r)
作为循环条件,确保在计算面积时,始终处理两条不同的线段。
6. 空间复杂度优化
- 仅使用常数额外空间(
l
,r
,ans
),空间复杂度为O(1)。
7. 时间复杂度分析
- 由于每个元素只被访问一次,算法的时间复杂度为O(n),其中n是数组的长度。