算法题 盛最多水的容器

11. 盛最多水的容器

问题描述

给定一个长度为 n 的整数数组 height,表示 n 条垂线的高度。找出两条垂线,使得它们与 x 轴共同构成的容器能容纳最多的水,返回最大容量。

示例
在这里插入图片描述

输入:height = [1,8,6,2,5,4,8,3,7]
输出:49
解释:垂线 1(高度 8)和垂线 8(高度 7)形成的容器容量为 7 * 7 = 49(表示为蓝色部分)

算法思路

双指针法

  1. 指针初始化
    • 左指针 left 指向数组起始位置
    • 右指针 right 指向数组末尾位置
  2. 容量计算
    • 当前容量 = min(height[left], height[right]) * (right - left)
  3. 指针移动规则
    • 移动高度较小的指针(因为容量受限于较小高度)
    • 目标:寻找更高的垂线以提升潜在容量
  4. 更新最大容量:每次计算后更新全局最大值

正确性

  • 每次移动较小高度的指针,保留了获得更大容量的可能性
  • 不会错过最优解,因为容量由较小高度决定
  • 时间复杂度 O(n),空间复杂度 O(1)

代码实现

class Solution {
    public int maxArea(int[] height) {
        int left = 0;                   // 左指针
        int right = height.length - 1;  // 右指针
        int maxArea = 0;                // 最大容量
        
        while (left < right) {
            // 计算当前容量
            int currentHeight = Math.min(height[left], height[right]);
            int width = right - left;
            int area = currentHeight * width;
            
            // 更新最大容量
            maxArea = Math.max(maxArea, area);
            
            // 移动较小高度的指针
            if (height[left] < height[right]) {
                left++;
            } else {
                right--;
            }
        }
        return maxArea;
    }
}

代码注释

代码部分说明
left = 0左指针初始位置
right = height.length - 1右指针初始位置
Math.min(height[left], height[right])容器有效高度
right - left容器宽度
area = currentHeight * width计算当前容量
Math.max(maxArea, area)更新全局最大容量
height[left] < height[right] ? left++ : right--移动较小高度的指针

算法过程

height = [1,8,6,2,5,4,8,3,7]

  1. 初始状态left=0 (h=1), right=8 (h=7)
    • 容量 = min(1,7)*8 = 8maxArea=8
    • 移动左指针(高度较小)
  2. 步骤1left=1 (h=8), right=8 (h=7)
    • 容量 = min(8,7)*7 = 49maxArea=49
    • 移动右指针
  3. 步骤2left=1 (h=8), right=7 (h=3)
    • 容量 = min(8,3)*6 = 18maxArea=49
    • 移动右指针
  4. 继续直至指针相遇,最终返回 49

复杂度分析

  • 时间复杂度:O(n)
    只需遍历数组一次
  • 空间复杂度:O(1)
    仅使用常数空间

关键点

  1. 双指针移动原理
    • 容量受限于较小高度,移动较小指针可能获得更大容量
    • 移动较大指针必然导致容量减小(宽度减小,高度不变或更小)
  2. 贪心策略
    • 每次移动都保留获得更大容量的可能性
    • 不会错过最优解
  3. 高效性
    • 只需一次扫描,无需额外空间
    • 比暴力法 O(n²) 显著优化

测试用例

public static void main(String[] args) {
    Solution solution = new Solution();
    
    // 示例测试
    int[] height1 = {1,8,6,2,5,4,8,3,7};
    System.out.println(solution.maxArea(height1)); // 49
    
    // 均匀高度测试
    int[] height2 = {5,5,5,5,5};
    System.out.println(solution.maxArea(height2)); // 20 (5*4)
    
    // 递增高度测试
    int[] height3 = {1,2,3,4,5};
    System.out.println(solution.maxArea(height3)); // 6 (min(2,5)*3=6)
    
    // 递减高度测试
    int[] height4 = {5,4,3,2,1};
    System.out.println(solution.maxArea(height4)); // 6 (min(5,1)*4=4 → min(5,2)*3=6)
    
    // 边界测试
    int[] height5 = {1,1};
    System.out.println(solution.maxArea(height5)); // 1
}

常见问题

  1. 为什么移动较小高度的指针?
    因为容量受限于较小高度。移动较小指针可能遇到更高垂线,从而增加容量潜力;而移动较大指针必然导致宽度减少,且高度不会增加(因为容量受限于较小高度)。

  2. 是否会错过最优解?
    不会。假设最优解为 (i,j),当指针移动到这对组合时,必然已经通过移动较小高度的策略到达该位置。

  3. 如何处理高度相等的情况?
    height[left] == height[right] 时,移动任意指针均可(因为无论移动哪边,宽度都减少1,但另一边高度不变,容量必然减小)。

  4. 最坏情况下的性能如何?
    最坏情况需要扫描整个数组(如单调递增/递减数组),时间复杂度 O(n),仍优于暴力法 O(n²)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值