LeetCode 11:盛最多水的容器(双指针问题) —— 题解

👋 欢迎阅读

一.题目

11. 盛最多水的容器 - 力扣(LeetCode)

🎯 欢迎来到「盛最多水的容器」题解之旅! 本文将带你从"寻找两条线与 x 轴构成的最大容器"这一几何直觉出发,深入理解双指针(对撞指针) 的经典应用,并掌握如何通过每次移动较短的边来高效逼近最优解。

在开始之前,建议你先:

  • 了解题目背景 :这是 LeetCode 11 题,给定数组 height,每个元素表示一根垂直线的高度,选择两根线与 x 轴构成容器,求能容纳的最大水量 (面积 = 宽度 × 高度,高度取两根线中较短者)。本质上,我们需要在 O(n)O(n) 时间内找到最大矩形面积,暴力枚举不可行,双指针是本题的核心解法。

  • 明确学习目标 :掌握双指针收缩策略 ------左指针指向数组左端,右指针指向右端,计算当前面积;然后移动高度较小的一端 (因为面积受限于较短边,移动较高边不会让面积增大,只有移动较短边才有可能遇到更高的边)。理解为什么这种"每次舍弃较短的边"的贪心策略能保证不漏掉最优解,并熟练实现循环与面积更新的代码逻辑。

  • 准备好环境 :建议在本地 IDE 或 LeetCode 在线编辑器中打开代码,边看边运行,亲手验证示例(如 height = [1,8,6,2,5,4,8,3,7] 输出 49)。

本文将从问题转化、双指针策略设计、正确性直觉 到代码实现,层层递进。即使你对双指针还不熟悉,我们也会从"容器高度取决于短板,想变大就要换掉短板 "这一直观出发,让你轻松抓住核心思想 ------每次向内移动较短的线,宽度虽减,但有机会遇到更高的线从而提升容量,而移动较长的线则不可能让容量变大。现在,让我们一起用两根指针扫描数组,找出那个能盛最多水的容器吧! 📏💧

二.做题思路

一、问题分析(前置分析)

给定一个整数数组 height,其中每个元素表示一条垂直线的高度,下标代表 x 轴坐标。选择两条线,与 x 轴构成容器,求 能容纳的最大水量

容量 = 宽度(两下标之差)× 高度(两条线中较矮的高度)

核心观察 :容器的容量由 较短的边 决定。要最大化面积,需要综合考虑宽度和高度。


二、算法策略(双指针)

  • 使用 左右双指针 leftright 分别指向数组的两端。

  • 循环条件left < right

  • 每次计算当前面积:area = min(height[left], height[right]) * (right - left),并更新最大面积 maxVal

  • 移动指针规则移动高度较小的那个指针 (即若 height[left] < height[right],则 left++;否则 right--)。

  • 直到两指针相遇,结束循环。


三、正确性说明(简单版本)

容器的高度由 较短的边 决定。若当前左指针高度小于右指针,则 移动右指针 (较高的边)时,宽度减小,而高度不会超过当前左指针的高度,因此面积只会减小或不变,不可能找到更大的面积。因此,移动较短的边 是唯一可能使面积增大的选择。这样逐步缩小搜索范围,不会遗漏任何可能的最大值,从而保证最终结果正确。


四、实现细节(边界防护)

  • 初始化 left = 0right = n-1maxVal = 0

  • 计算宽度时使用 right - left

  • 高度取 min(height[left], height[right])

  • 更新最大值后,根据比较结果移动指针。

  • 循环直到 left == right

  • 时间复杂度 O(n),空间复杂度 O(1)。


五、返回值(目标映射)

返回 maxVal,即 能容纳的最大水量

三.代码

cpp 复制代码
class Solution 
{
public:
    int maxArea(vector<int>& height) 
    {
        // 算法思路:双指针法
        // 左指针指向数组左端,右指针指向数组右端。
        // 计算当前左右指针所构成的容器面积 = min(height[left], height[right]) * (right - left)。
        // 然后移动高度较小的指针(因为容器面积受限于较短边,移动较高边不会使面积增大,只有移动较短边才可能找到更大的面积)。
        // 直到左右指针相遇,过程中记录最大面积。

        int n = height.size();
        int left = 0;          // 左指针,初始指向最左边
        int right = n - 1;     // 右指针,初始指向最右边

        int maxVal = 0;        // 记录当前找到的最大矩形面积(避免与 std::max 冲突,用 maxVal)

        // 当左指针小于右指针时,持续计算面积
        while (left < right) 
        {
            // 取当前左右指针中较小的那个高度(因为容器的宽度取决于较短边)
            int rectangle_wide = 0;
            if (height[left] < height[right]) 
            {
                rectangle_wide = height[left];
            } 
            else 
            {
                rectangle_wide = height[right];
            }

            // 容器的长度(底边宽度)为右指针与左指针的差值
            int rectangle_long = right - left;
            int new_max = rectangle_long * rectangle_wide;

            // 更新最大面积
            if (new_max > maxVal) 
            {
                maxVal = new_max;
            }

            // 移动指针的策略:移动高度较小的那一端,以期望找到更高的边,从而可能增大面积
            if (height[left] < height[right]) 
            {
                left++;   // 左边较低,左指针向右移动
            } 
            else 
            {
                right--;  // 右边较低(或相等,移动任意一边),右指针向左移动
            }
        }

        // 返回最大面积
        return maxVal;
    }
};

四、流程图

🎯 闭幕

🎉 恭喜你完成了「盛最多水的容器」问题的学习!

为了巩固知识并进一步拓展,建议你:

🚀 动手实践

在 LeetCode 上提交代码,尝试不同的测试用例。

💡 深入思考

  • 本题使用 双指针 从数组两端向中间收缩。为什么移动指针时,要选择 移动高度较小的那一边 ,而不是高度较大的那一边?请从 面积计算公式 的角度解释原理。

  • 如果左右指针高度 相等 时,代码中选择了移动右指针(right--),那么移动左指针是否也可以?这两种选择对最终结果有影响吗?

  • 双指针法的 时间复杂度为 O(n) ,而暴力枚举所有组合为 O(n²)。请说明为什么移动指针的过程中 不会遗漏 可能的最优解?

📚 延伸挑战

  • 如果题目改为 找出面积最大的三个柱子构成的容器(即选择三条线,取最左和最右为边界,中间柱子不影响面积),算法该如何改造?

  • 如果允许 倾斜容器(即容器可以倾斜,盛水量不再由最短边决定),问题会变得怎样?为什么题目要特别说明"不能倾斜容器"?

如果你觉得本文对你有所帮助,欢迎:

👍 点赞 / 收藏

👤 关注作者 ,获取更多题解

💬 留言交流你的疑问或优化思路


📌 深入思考答案

  • 移动较矮边 是因为容器的盛水量由 较短边 决定(短板效应),若移动较高边,宽度减小而高度不变或更低,面积只会 减少或不变 ;只有移动较矮边,才有机会遇到更高的边,从而 增大面积

  • 高度相等时,移动左指针或右指针 均可 ,因为无论移动哪一边,宽度都在减小,而高度受限于相等的值,后续面积不会超过当前值,因此选择任意一边对最终结果 没有影响

  • 双指针 不会遗漏最优解 ,因为每一步移动较矮边时,相当于 排除了该边与其他所有边组合的可能性,而这些被排除的组合的面积都不会超过当前面积(由于宽度更大但高度受限于该矮边),因此安全剪枝。

🔍 延伸挑战答案

  • 挑战1 :若选择三条线,实际盛水仍由 最左和最右 两条边界决定,中间线不参与盛水,因此问题退化为原问题,只需找到最优的两条边界,中间选任意一条不影响结果,算法无需改动。

  • 挑战2 :若允许倾斜,盛水量将不再由最短边决定,而是由倾斜后液面与容器壁的接触位置决定,问题复杂度剧增,需引入 流体力学模型几何计算 ,不再适合用双指针简单求解;题目限定"不能倾斜"正是为了保持问题的 几何简洁性

祝你在 算法之路 上越走越稳,早日攻克每一道难题!下次见 🚀✨

相关推荐
C++ 老炮儿的技术栈1 小时前
从 Qt Designer 属性编辑器的层级可以看到继承链
c语言·数据库·c++·qt·sqlite·visual studio
MC皮蛋侠客1 小时前
Redis 系列(一):全景与最小闭环——从 `SET` 命令到内存数据结构
数据结构·数据库·redis
疯狂打码的少年1 小时前
【数据结构】队列:定义、顺序队列与链式队列
数据结构·笔记
new_zhou1 小时前
C++ 项目 AI 协作指南(Windows / MSVC 环境)
c++·人工智能·windows
地平线开发者1 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者1 小时前
【征程6】校准量化中HistogramObserver解析
算法
蔬菜_2 小时前
前端转全栈-day5(数组、list、set)
java·前端·数据结构·list
OuO-22 小时前
笔试强训 Day 34:ISBN 号码、kotori 和迷宫、矩阵最长递增路径
java·算法·矩阵
水饺编程3 小时前
AT&T 汇编语言学习笔记开篇语
c语言·汇编·c++
Iruoyaoxh3 小时前
类和对象~
开发语言·c++