[C++算法]盛最多水的容器(双指针算法)

前言

「盛最多水的容器」是力扣上一道经典的双指针题目。给定一个整数数组,数组中的每个值代表一根垂直于 x 轴的柱子高度,我们需要从中选出两根柱子,使它们与 x 轴围成的容器能够容纳最多的水。这个问题看似需要枚举所有柱子组合,但借助双指针的单调性,可以在一次遍历内高效求解。

双指针解法的核心思想是:从数组两端各放一个指针,每次比较两根柱子的高度,移动较矮一侧的指针向内收缩。因为容器的高度由较短的柱子决定,移动较矮一侧才有可能让高度变大,从而获得更大的容积。通过不断更新最大体积,最终得到答案。

题目描述:

题目来源:力扣「盛最多水的容器」

给定一个长度为 n 的整数数组 height。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

找出其中的两条线,使它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明: 你不能倾斜容器。

横坐标表示数组的下标 i,纵坐标表示数组的值即 nums[i]

算法原理:

利用单调性,采用双指针的算法解决此问题。

值得注意的是"盛水的体积大小取决于最短的那块木板"。

笔记:盛最多水的容器(双指针解法)

题目核心

容器盛水量公式:V = h × w

  • w:左右两个柱子之间的宽度(下标之差)
  • h:容器高度,由左右两根柱子中较短的那一根决定

示例数组:[1, 8, 6, 2, 5, 4, 8, 3, 7]

双指针思路

  1. 初始化:左指针 left 放在数组最左端,右指针 right 放在数组最右端。
  2. 循环终止条件:leftright 相遇时停止。
  3. 指针移动规则:比较左右两个柱子高度,移动高度更小的那一侧指针向内收缩

分步图解示例

以示例数组 [1, 8, 6, 2, 5, 4, 8, 3, 7] 为例,逐步演示双指针的移动过程。下表记录了每一步中左右指针的位置、对应柱子高度、容器宽度、当前体积以及历史最大体积。

步骤 left right heightleft heightright 宽度 w 体积 V 最大体积 Vmax 移动指针
1 0 8 1 7 8 8 8 left++
2 1 8 8 7 7 49 49 right--
3 1 7 8 3 6 18 49 right--
4 1 6 8 8 5 40 49 left++
5 2 6 6 8 4 24 49 left++
6 3 6 2 8 3 6 49 left++
7 4 6 5 8 2 10 49 left++
8 5 6 4 8 1 4 49 left++

从表格中可以看到,当 left 指向下标 1(高度 8)、right 指向下标 8(高度 7)时,容器体积达到最大值 49,这也是本题的最终答案。整个过程中,左右指针从两端向中间靠拢,每个元素最多被访问一次,因此时间复杂度为 O(n)

移动原理(单调性)

向内收缩时,宽度 w 一定会变小,分两种情况:

  1. 若移动较短柱子,新柱子高度 > 当前短柱高度:高度 h 不变,但宽度 w 减小,总体积 V 变小;
  2. 若移动较短柱子,新柱子高度 < 当前短柱高度:高度 h 减小,宽度 w 也减小,总体积 V 变小。

长柱子一侧不用移动:因为当前短柱已经限制了容器高度,向内移动长柱子只会让宽度变小,不可能得到更大的容积。所以直接舍弃当前较短的柱子,向内移动指针。

  1. 每次移动指针后,重新计算当前容器体积,持续更新记录最大体积 Vmax
cpp 复制代码
class Solution 
{
public:
    int maxArea(vector<int>& height) 
    {
        int left = 0;
        int right = height.size()-1;
        //记录体积的最大值
        int ret = 0;
        while(left < right)
        {
            //宽度为左减去右
           int v = min(height[left],height[right])*(right -left);
           //计算完体积 更新一下最大的体积
           ret =max(v,ret);
           //移动指针
            if(height[left]<height[right])
            {
                left++;
            }
            else
            {
                right--;
            }
        }
        return ret;

    }
};

复杂度分析

双指针解法的时间复杂度为 O(n),空间复杂度为 O(1)

时间复杂度为 O(n) 的原因:左右指针分别从数组两端出发,每次循环只移动其中一个指针,且两个指针相遇时循环结束。在整个过程中,每个元素最多只会被访问一次,因此总的操作次数与数组长度 n 成正比。

空间复杂度为 O(1) 的原因:算法只使用了 leftrightret 等常数个额外变量,没有借助额外的数据结构,因此空间占用与输入规模无关。

总结

双指针解法是解决「盛最多水的容器」问题的高效方法,其关键在于利用容器的短板效应:每次移动较矮一侧的指针,在宽度减小的同时有机会提升容器高度,从而在 O(n) 时间内找到最大容积。

该解法适用于需要在一维数组中寻找满足某种约束的最优区间问题,尤其是当问题具有单调性、且最优解可以通过收缩边界逐步逼近时。理解这一思路,有助于举一反三地解决其他双指针类题目。

相关推荐
泡海椒1 小时前
jquick-pdf 文本元素实战:段落、行内文本、制表符用法详解
java·开发语言·pdf
布莱克6051 小时前
理解内存泄漏:成因、发现方法与解决策略(C++ 举例)
c语言·c++·内存泄漏
“AI国潮设计-小江”2 小时前
【SDXL实战】Python自动化生成3D潮汕美食IP,附ComfyUI工作流与商用变现思路
开发语言·人工智能·python·prompt·aigc
不会就选b2 小时前
算法日常・每日刷题--<贪心>15
算法
此生决int2 小时前
深入理解C++系列(19)——C++11(上)
开发语言·c++
鹿角片ljp2 小时前
Prompt Cache、Token 成本与 Plan Compiler 的工程设计
java·python·算法
郝学胜-神的一滴2 小时前
C++20模板元编程 05:吃透变参模板,解锁编译期万能参数能力
服务器·开发语言·c++·windows·vscode
萧西待水9 小时前
奥赛一本通 1447 靶形数独
算法·深度优先
泯泷11 小时前
那段文字是谁删的?Yjs 14 正式版之前,一套删除归属方案的实现与边界
前端·javascript·算法