hot100 盛最多水的容器(11)
一、 算法核心思想
该算法的核心在于双指针(Two Pointers)与贪心策略。
容器的容量由两个因素决定:
-
底部的宽度:左右指针之间的距离 (right−left)。
-
容器的高度:左右两条垂线中的较低者 min(height[left],height[right])。
水量的计算公式为:
Area=(right−left)×min(height[left],height[right])
指针移动逻辑
算法初始时将 left 指向数组首端,right 指向数组尾端。此时容器的宽度达到最大。随后指针向内移动,宽度必然减小。为了寻找可能更大的面积,必须提升容器的高度。因此,每次移动时,哪侧的垂线较低,就移动哪侧的指针:
-
如果 height[left]<height[right],则
left++ -
如果 height[left]≥height[right],则
right--
二、 代码逐行拆解与执行流程
class Solution {
public int maxArea(int[] height) {
// 1. 初始化双指针,分别指向数组的起始位置和结束位置
int left = 0;
int right = height.length - 1;
// 2. 初始化最大水面积变量
int ans = 0;
// 3. 当左右指针未相遇时执行循环
while (left < right) {
// 4. 计算当前指针位置构成的容器面积
int area = (right - left) * Math.min(height[left], height[right]);
// 5. 更新历史最大面积
ans = Math.max(ans, area);
// 6. 贪心策略:移动高度较小的指针
if (height[left] < height[right]) {
left++; // 左指针向右移动
} else {
right--; // 右指针向左移动
}
}
// 7. 返回最终计算出的最大面积
return ans;
}
}
三、 贪心策略的正确性证明(为什么可以漏掉其余状态)
设左指针指向的基准高度为 x=height[left],右指针指向的基准高度为 y=height[right]。
假设此时 x<y,即左边界较短。 若固定左边界 left,将右边界 right 向内移动到 right−1:
-
新的宽度一定会减少。
-
新的高度最大不会超过 x(因为即便 height[right−1] 非常大,容器高度依然受限于短板 x)。
因此,在 left 不变的情况下,排除内部所有的右边界状态,其对应的面积都必然小于当前面积:
Areanew≤(right−1−left)×x<(right−left)×x
这意味着以当前 left 为左边界的所有其他组合都不可能产生更大的面积。因此,直接放弃 left 并执行 left++ 是完全正确的,不会漏掉最优解。
四、 复杂度分析
1. 时间复杂度
-
分析:双指针
left和right分别从数组的两端出发,每一步循环都有且仅有一个指针向内移动一个单位。 -
总步数:两指针相遇时循环结束,指针移动的总次数为 n−1 次。
-
结论:时间复杂度为 O(n),其中 n 为数组
height的长度。
2. 空间复杂度
-
分析:算法在运行过程中只创建了
left、right、ans、area这四个整型变量。 -
变动情况:所分配的辅助空间不随输入数据规模 n 的增大而增大,属于常数级额外空间。
-
结论:空间复杂度为 O(1)。
更多推荐
所有评论(0)