算法步骤

  1. 初始化:左指针在数组开头,右指针在数组末尾

  2. 循环计算:当左指针 < 右指针时

    • 计算当前左右指针围成的面积:(距离) × (较矮的高度)

    • 更新最大面积

    • 移动较矮的那一边指针(因为移动较高的那边不会增加面积)

关键逻辑

  • 面积计算:(right - left) × min(height[left], height[right])

  • 指针移动策略:总是移动较矮的那一边

    • 因为容器的盛水量由较矮的那边决定

    • 移动较矮的指针有可能找到更高的边界,从而增加面积

    • 移动较高的指针只会让面积不变或减小

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    //贪心思想上看:我们要找到两根最高的 两根间距离最长的
    //如果只找最高的 考虑失效的情况:[2,4,5,8,3] --->选择5,8 容纳了5的水 但实际最优是4,3 容纳9的水
    ans = 0;
    max = 0;
    left = 0;
    right = height.length - 1;
    while(left<right){
        ans = (right-left) * Math.min(height[left],height[right]);
        max = Math.max(ans,max);
        if(height[left]<height[right])
            left++;
        else
            right--;
    }
    return max;
};

数据测试逐步解析

测试数据:[1,8,6,2,5,4,8,3,7]

步骤leftright高度[left]高度[right]距离较矮高度当前面积最大面积移动方向
108178188left++
21887774949right--
31783631849right--
41688584049left++ 或 right--
52668462449left++
6362832649left++
74658251049left++
8564814449left++

最终结果:49(对应 left=1, right=8 时的容器)


简单案例:[1,2,4,3]

步骤leftright高度距离较矮高度当前面积最大面积移动方向
1031,33133left++
2132,32244left++
3234,31334right--

最终结果:4(对应 left=1, right=3 时的容器)

为什么移动较矮的指针?

考虑两种情况:

  • 如果移动较高的指针:距离减小,高度不会超过当前较矮的高度,面积必然减小

  • 如果移动较矮的指针:距离减小,但可能找到更高的边界,面积有可能增加

时间复杂度

  • O(n):每个指针最多移动n次

  • O(1):只使用了常数空间

更多推荐