双指针法是一种能将O(n2)O(n^2)O(n2) 复杂度降低到 O(n)O(n)O(n) 的神技。LeetCode 第 11
题“盛最多水的容器”正是理解双指针移动逻辑、掌握“贪心思想”排除无效搜索空间的经典案例。

题目回顾

给定一个长度为 nnn 的整数数组 height。有 nnn 条垂线,第 iii 条线的两个端点是 (i,0)(i, 0)(i,0)(i,height[i])(i, height[i])(i,height[i])。找出其中的两条线,使得它们与 xxx 轴共同构成的容器可以容纳最多的水。

示例:
在这里插入图片描述

输入: [1,8,6,2,5,4,8,3,7]

输出: 49

解释: 数组中索引 1(高度 8)和索引 8(高度 7)之间的容器面积最大。宽度为 8−1=78 - 1 = 781=7,高度取两者较小值 min⁡(8,7)=7\min(8, 7) = 7min(8,7)=7,面积 7×7=497 \times 7 = 497×7=49

解题思路分析:

为什么要用双指针?

计算容器面积的公式非常直观:Area=min⁡(height[l],height[r])×(r−l)Area = \min(height[l], height[r]) \times (r - l)Area=min(height[l],height[r])×(rl)如果要暴力枚举所有可能的组合,需要两层 for 循环,时间复杂度为 O(n2)O(n^2)O(n2)。但在 n=105n=10^5n=105 的数据规模下,这显然会超时。
我们需要一种更聪明的策略。

核心逻辑:移动“较短”的那一侧

我们设置两个指针 lllrrr 分别指向数组的两端。此时,宽度 (r−l)(r - l)(rl) 是最大的。接下来我们要向内收缩,宽度一定会减小。为了弥补宽度的损失,我们必须寻找更高的柱子。

  • 如果移动长柱子: 容器的高度由短柱子决定,移动长柱子后,新高度绝不会超过原有的短柱子,而宽度又减小了,面积必然变小。
  • 如果移动短柱子: 虽然宽度减小了,但我们有可能遇到一根更长的柱子,从而使得 min⁡(height[l],height[r])\min(height[l], height[r])min(height[l],height[r])
    增大,面积有可能增大。

这种“舍弃当前最短板”的操作,本质上是排除了所有以当前短柱子为边界的无效组合,从而在 O(n)O(n)O(n) 时间内找到最优解。

Go 语言代码实现

func maxArea(height []int) int {
    var l int = 0
    var r int = len(height)-1
    var max0 = 0
    for l!=r{
        max0 = max(max0,min(height[r],height[l])*(r-l))
        if(height[l]<height[r]){
            l++
        }else{
            r--
        }
        
    }
    return max0
}

更多推荐