一、 算法核心思想

该算法的核心在于双指针(Two Pointers)贪心策略

容器的容量由两个因素决定:

  1. 底部的宽度:左右指针之间的距离 (right−left)。

  2. 容器的高度:左右两条垂线中的较低者 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. 时间复杂度

  • 分析:双指针 leftright 分别从数组的两端出发,每一步循环都有且仅有一个指针向内移动一个单位。

  • 总步数:两指针相遇时循环结束,指针移动的总次数为 n−1 次。

  • 结论:时间复杂度为 O(n),其中 n 为数组 height 的长度。

2. 空间复杂度

  • 分析:算法在运行过程中只创建了 leftrightansarea 这四个整型变量。

  • 变动情况:所分配的辅助空间不随输入数据规模 n 的增大而增大,属于常数级额外空间。

  • 结论:空间复杂度为 O(1)。

更多推荐