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

力扣hot100-------11、盛最多水的容器(java版)

1、题目描述

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (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。

示例 2:

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

2、思路

 一、思路分析:为什么用“双指针”?

1. 暴力法的缺陷

最直接的想法是:

枚举所有 (i, j) 组合,计算面积,取最大值。

for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {area = min(height[i], height[j]) * (j - i);maxArea = max(maxArea, area);}}
  • 正确性没问题。

  • 时间复杂度 O(n²),当 n=10⁵ 时,操作次数 ≈ 50 亿 → 超时!


2. 优化方向:能不能“跳过”一些组合?

我们发现:

容器面积 = 宽度 × 高度

宽度 = j - i

高度 = min(height[i],height[j])

 面积受限于较短的那条边

3. 双指针的核心思想(贪心 + 缩小搜索空间)

策略

  • 初始化:left = 0, right = n - 1(最大宽度)

  • 每次计算当前面积,更新最大值

  • 移动“较短”的那根柱子的指针

为什么?因为:

  • 如果你移动“较高的”那根 → 宽度减小,高度不会增加(甚至可能更小)→ 面积不可能变大

  • 如果你移动“较短”的那根 → 宽度减小,但高度有可能变大 → 面积有可能变大!

理解:“宽度注定越来越小,我们只能赌高度能变大 —— 而只有移动短板,才有机会让‘决定高度的那根线’变高。移动长板,高度不会变高,面积只会更小 —— 所以果断放弃长板,搏一搏短板!

这是一种“贪心策略”:每次放弃当前不可能产生更大面积的一侧,向内收缩,保留希望更大的一侧。

4. 为什么不会错过最优解?

这是最关键的问题!

证明思路(反证法):

假设真正的最大面积是由 i=aj=b 形成的(a < b),但在双指针移动过程中,其中一个指针提前越过了 a 或 b。

但在移动过程中:

  • 只有当某侧是“当前较短边”时才会移动它。

  • left=a, right=b 时,一定会被计算一次!

  • 在那之前,如果 left right 被移动了,说明那一侧是“更短”的,而根据面积公式,它和任何中间柱子形成的面积都不可能比当前 (a,b) 更大 —— 所以提前移动它不会错过最优解

所以,双指针法不会漏掉最大面积组合

二、边界条件分析

while (left < right)
  • 循环条件left < right

    • left == right 时,宽度为 0,面积为 0 → 无需计算

    • 所以必须是严格小于

  • 指针移动边界

    • left 最大移动到 n-2(当 right = n-1)

    • right 最小移动到 1(当 left = 0)

    • 永远不会越界,因为 left < right 保证了 left <= n-2, right >= 1

  • 数组长度边界

    • 题目隐含 n >= 2(否则无法形成容器)

    • 但保险起见,可以加判断:

if (height == null || height.length < 2) return 0;

 三、完整 Java 代码 + 注释

 class Solution {public int maxArea(int[] height) {// 边界判断:数组为空或长度不足2,无法构成容器if (height == null || height.length < 2) {return 0;}int left = 0;               // 左指针int right = height.length - 1; // 右指针int maxArea = 0;            // 最大面积// 双指针向中间收缩,直到相遇while (left < right) {// 计算当前容器面积:高度取短板,宽度为 right - leftint currentHeight = Math.min(height[left], height[right]);int currentWidth = right - left;int currentArea = currentHeight * currentWidth;// 更新最大面积maxArea = Math.max(maxArea, currentArea);// 移动较短边的指针,希望找到更高的边if (height[left] < height[right]) {left++;  // 左边矮,移动左指针} else {right--; // 右边矮(或相等),移动右指针}}return maxArea;}}

四、涉及的 Java 知识点讲解

1. 数组(Array)

 int[] height
  • Java 中的数组是定长的,创建后长度不可变。

  • 访问元素:height[i],索引从 0length - 1

  • 获取长度:height.length(注意不是方法,是属性)

2. Math 类的静态方法

 Math.min(a, b)Math.max(a, b)
  • Math 是 Java 的工具类,提供数学运算方法。

  • 所有方法都是 static,直接用类名调用。

  • min / max:比较两个数,返回较小/较大值。

3. while 循环控制

while (left < right) { ... }
  • 条件为真时重复执行循环体

  • 每次循环必须让 left++right--,否则会死循环

  • 循环结束条件明确:left >= right

4. 变量作用域与初始化

 int left = 0;int right = height.length - 1;int maxArea = 0;
  • 局部变量必须初始化后才能使用

  • Java 不允许使用未初始化的局部变量(编译报错)

5. 方法定义与返回值

 public int maxArea(int[] height)
  • public:访问修饰符,表示公开方法

  • int:返回类型

  • maxArea:方法名

  • int[] height:参数,传入一个整型数组

  • return maxArea;:返回计算结果

6. 条件语句 if-else

if (height[left] < height[right]) {left++;
} else {right--;
}
  • 用于二选一逻辑判断

  • 注意:当两边相等时,移动哪边都可以(因为另一边也不会更大了)

 五、算法复杂度总结

项目说明
时间复杂度O(n) —— 只遍历一次
空间复杂度O(1) —— 只用几个变量
是否最优 是已知最优解
是否稳定 每次结果相同,无随机性

 六、举个实际运行例子

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

步骤leftright高度宽度面积maxArea移动哪边
108min(1,7)=1888left++
218min(8,7)=774949right--
317min(8,3)=361849right--
416min(8,8)=854049任意
526min(6,8)=642449left++
..................49...

最终结果:49


总结:为什么要用双指针?

原因说明
时间效率高O(n) vs O(n²),大数据下性能差距巨大
空间效率高只用常数空间,不依赖额外数据结构
思维巧妙利用“短板效应” + “贪心移动”,每次排除不可能最优的一侧
面试高频考点几乎所有大厂算法面试都会考,是“双指针”经典入门题
可扩展性强思想可用于“接雨水”、“三数之和”、“有序数组两数之和”等经典问题

 

http://www.dtcms.com/a/552846.html

相关文章:

  • Visual Basic 菜单编辑器
  • 本地部署轻量级持续集成工具 Drone CI 并实现外部访问
  • gitlab-ci中cicd+helm实现devops自动化部署到k8s
  • 网站欢迎页面怎么做江门建站公司模板
  • 评论回复网站怎么做郑州百度搜索优化
  • Rust开发之使用derive宏自动实现Trait(Clone、Debug)
  • 15. setState的更新是异步的吗
  • Qwen2.5-VL开源,斩获多榜单冠军!
  • Prometheus和Grafana简介
  • 基于深度学习的医疗器械分类编码映射系统:设计篇
  • Rust开发之自定义错误类型(实现Error trait)
  • 【Java Web学习 | 第三篇】CSS(2) - 元素显示模式
  • 10月31日
  • Mybatis-Plus实现MySQL分表
  • 兵团住房和城乡建设局网站网站设计标杆企业
  • 快充新标杆:AVS 协议如何重塑手机充电体验
  • LIUNX 与手机安卓的文件互传 的常用方法
  • 第一届数证杯做题笔记(流量分析和手机取证)
  • 【IO多路转接】深入解析 poll:从接口到服务器实现
  • 【Spring Boot】Spring Boot解决循环依赖
  • 网站开发发展趋势2018网上建立网站赚钱
  • SuperMap Hi-Fi 3D SDK for Unreal 使用蓝图接口加载多源数据
  • 【Java】如何使用jdbc连接并操作MySQL,一文读
  • SSM宠物寄养系统ih041gj7(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 网站广告素材php网站免费模板
  • 还在用JDK8?JDK8升级JDK11:一次价值千万的升级指南
  • 深圳网站建设模板乐云seo与设计行业相关的网站
  • 缓存异常:缓存穿透、缓存击穿、缓存雪崩
  • 【计算机网络】IO复用方法(二)——Select
  • 【Java EE进阶 --- SpringBoot】统一功能处理(拦截器)