ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

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

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 轴构成容器求能容纳的最大水量。容量 宽度两下标之差× 高度两条线中较矮的高度。核心观察容器的容量由较短的边决定。要最大化面积需要综合考虑宽度和高度。二、算法策略双指针使用左右双指针left和right分别指向数组的两端。循环条件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即能容纳的最大水量。三.代码class Solution { public: int maxArea(vectorint 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若允许倾斜盛水量将不再由最短边决定而是由倾斜后液面与容器壁的接触位置决定问题复杂度剧增需引入流体力学模型或几何计算不再适合用双指针简单求解题目限定“不能倾斜”正是为了保持问题的几何简洁性。祝你在算法之路上越走越稳早日攻克每一道难题下次见 ✨
返回列表