当前位置: 首页 > news >正文

【每日一道算法题 day5】盛最多水的容器 (Container With Most Water) - LeetCode 题解

盛最多水的容器 (Container With Most Water) - LeetCode 题解

题目描述

给定一个长度为 n 的整数数组 height,其中 n 条垂线的两个端点分别是 (i, 0)(i, height[i])。找出两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水,返回容器可以储存的最大水量。

注意:容器不能倾斜。

示例 1:

输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水的最大值为 49。

图1

示例 2:

输入:height = [1,1]
输出:1

解题思路

方法一:双指针法(最优解)

  1. 初始化指针

    • left 指针从数组开头(0)开始
    • right 指针从数组末尾(len(height)-1)开始
  2. 计算面积

    • 当前面积 = min(height[left], height[right]) * (right - left)
    • 更新最大面积
  3. 移动指针

    • 移动高度较小的指针(因为移动高度较大的指针不可能得到更大的面积)
    • 如果两指针高度相同,可以移动任意一个
  4. 终止条件

    • leftright 指针相遇时结束
  5. 复杂度分析

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

方法二:暴力法(不推荐)

  1. 双重循环

    • 遍历所有可能的线对组合
    • 计算每对线构成的容器面积
    • 记录最大面积
  2. 缺点

    • 时间复杂度:O(n²)
    • 空间复杂度:O(1)
    • 不适用于大规模数据

Go 代码实现

双指针法实现

func maxArea(height []int) int {maxArea := 0left, right := 0, len(height)-1for left < right {h := min(height[left], height[right])width := right - leftarea := h * widthif area > maxArea {maxArea = area}if height[left] < height[right] {left++} else {right--}}return maxArea
}func min(a, b int) int {if a < b {return a}return b
}func main() {height := []int{1, 8, 6, 2, 5, 4, 8, 3, 7}result := maxArea(height)println("Max area:", result) // 输出: 49
}

暴力法实现(对比)

func maxAreaBruteForce(height []int) int {maxArea := 0for i := 0; i < len(height); i++ {for j := i + 1; j < len(height); j++ {h := min(height[i], height[j])width := j - iarea := h * widthif area > maxArea {maxArea = area}}}return maxArea
}

测试用例

func TestMaxArea(t *testing.T) {tests := []struct {input  []intexpect int}{{[]int{1, 8, 6, 2, 5, 4, 8, 3, 7}, 49},{[]int{1, 1}, 1},{[]int{4, 3, 2, 1, 4}, 16},{[]int{1, 2, 1}, 2},{[]int{}, 0},{[]int{1}, 0},}for _, tt := range tests {got := maxArea(tt.input)if got != tt.expect {t.Errorf("maxArea(%v) = %d, want %d", tt.input, got, tt.expect)}}
}

复杂度分析

  1. 双指针法

    • 时间复杂度:O(n),只需一次遍历
    • 空间复杂度:O(1),只使用了常数空间
  2. 暴力法

    • 时间复杂度:O(n²),双重循环
    • 空间复杂度:O(1)

算法正确性证明

双指针法的正确性基于以下观察:

  1. 面积公式:面积 = min(height[left], height[right]) * (right - left)
  2. 移动策略:每次移动高度较小的指针
    • 因为移动高度较大的指针不可能得到更大的面积(宽度减小,高度受限于较小值)
    • 只有移动较小指针才有可能找到更高的边界

优化思路

  1. 提前终止

    • 当剩余宽度 * 最大可能高度 <= 当前最大面积时,可以提前终止
  2. 跳过重复计算

    • 如果移动指针后高度不比之前高,可以继续移动直到找到更高的边界

总结

这道题是典型的双指针应用问题,展示了如何通过巧妙的指针移动策略将O(n²)的暴力解法优化为O(n)的高效解法。关键在于理解为什么可以安全地移动高度较小的指针而不遗漏可能的更大面积。

掌握这种双指针技巧对解决类似的数组和容器类问题(如接雨水问题、两数之和等)非常有帮助。

扩展思考

  1. 如果要求找出所有可能的容器组合(而不仅仅是最大面积),该如何修改算法?
  2. 如何修改算法以处理高度可能为负数的情况?
  3. 如果容器可以倾斜(即可以形成梯形),该如何计算最大面积?
http://www.dtcms.com/a/342887.html

相关文章:

  • 深度学习之NLP基础
  • 【React】tab切换功能和排序实现,classnames工具优化类名控制
  • Java基础环境jdk和maven安装及配置+开源项目下载及编译打包教程
  • Flutter如何通过GlobalKey调用组件内的方法
  • 微服务的编程测评系统13-我的竞赛列表-elasticSearch
  • 与H5交互,与flutter的交互
  • 求解三位数
  • 深度解析DeepSeek V3.1 :6850 亿参数开源模型如何以 71.6% 编码得分、68 倍成本优势重构全球 AI 竞争格局
  • 使用postman模拟http请求webservice服务
  • 企业如何用外贸进销存系统管理好库存产品?
  • Docker安装elasticsearch以及Kibana、ik分词器
  • 从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(十三)
  • 相似图像处理程序
  • mac的m3芯使用git
  • 1.2 亿篇论文数据集,多学科学术语料库,涵盖医学、化学、生物学、人文、物理、工程、数学、生态、经济与计算机科学,用于 NLP、知识图谱与大模型训
  • 意象驱动的深层语义:感知认知统一对自然语言处理与知识图谱的影响
  • 数据结构——二叉树(Binary Tree)
  • 自然语言处理NLP L4: 高级语言模型——四种泛化平滑方式
  • Spring全家桶之全局异常处理
  • Spring Boot生态中ORM对数据治理的支持有哪些?
  • Ubuntu22.04配置网络上网
  • linux-ubuntu里docker的容器portainer容器建立后如何打开?
  • Maven无法修改镜像,镜像在IDEA里不生效
  • 室外和室内 PoE 延长器有什么区别?
  • [CSP-J2020] 直播获奖
  • 集成学习:从原理到实战,一文掌握 Bagging、Boosting 与 Stacking
  • 集成学习:如何让多个 “弱模型” 变成 “强模型”?
  • demo 汽车之家(渲染-筛选-排序-模块抽离数据)
  • Linux之Ansible自动化运维(二)
  • Linux内核源码详解--缺页异常(Page Fault)处理的核心函数handle_pte_fault