11.双指针—盛最多水的容器

要找到能容纳最多水的两条垂线,核心思路是利用双指针法(贪心策略),因为容器的盛水量由两个因素决定:
1、宽度:两条垂线的下标差(right-left);
2、高度:两条垂线中较短的那一条(min(height[left],height[right]));
3、水的体积:max(current_water,max_water); (体积:current_water=width*current_height; 有效高度:current_height=min(height[left],height[right])

双指针法的核心逻辑:

  • 初始化左指针在数组开头(lest=0),右指针在数组末尾(right=n-1);
  • 计算当前容器的盛水量,记录最大值;
  • 移动较短的那一侧的指针(因为移动较长侧的指针,宽度减小但高度不会增加,盛水量必然较小,而移动较短侧的指针,可能找到更高的垂线,从而增加盛水量);
  • 重复上述步骤,直到左右指针相遇。

这种方法只需遍历数组一次,时间复杂度O(n),空间复杂度O(1),是最优解。

以下是完整的代码实现:
#include
#include // 用于min和max函数
using namespace std;

int maxArea(vector& height) { //这个数组其实就是记录容器中水的高度,下标是每条水柱高度的编号
int left = 0;//左指针:初始在数组开头
int right = height.size() - 1; //右指针:初始在数组末尾
int max_water = 0; //记录最大盛水量

while (left < right) {
//计算当前容器的宽度
int width = right - left;
//计算当前容器的有效高度(较短的垂线)
int current_height = min(height[left], height[right]);
//计算当前盛水量
int current_water = width * current_height;
//更新最大盛水量
max_water = max(max_water, current_water);

//贪心移动指针:移动较短的一侧
if (height[left] < height[right]) {
left++;
}
else {
right--;
}
}
return max_water;
}

int main() {
// 示例1:常规情况
vector height1 = { 1,8,6,2,5,4,8,3,7 };
cout << "最大盛水量:" << maxArea(height1) << endl; // 输出49

}

代码关键部分解释:
int left = 0;
int right = height.size() - 1;
while (left < right) { ... }
左指针从最左开始,右指针从最右开始,循环终止条件是 left >= right(两指针相遇,无法构成容器)。

盛水量计算:
int width = right - left;
int current_height = min(height[left], height[right]);
int current_water = width * current_height;
容器的宽度是两指针的下标差,高度由 “短板” 决定(因为水的高度不会超过较短的垂线),这是盛水量计算的核心公式

贪心移动指针
if (height[left] < height[right]) {
left++;
} else {
right--;
}
为什么移动较短侧的指针?
假设左指针的垂线更短:如果移动右指针,宽度减小,而高度最多还是左指针的高度(短板没变),盛水量必然减少;如果移动左指针,可能找到更长的垂线,短板可能变长,盛水量可能增加。
反之同理,这是贪心策略的关键,能保证不遗漏最优解。

posted @ 2026-03-24 10:43  ZealousMclaren  阅读(15)  评论(0)    收藏  举报