class Solution { public int maxArea(int[] height) { //1.暴力求解法(超出时间限制) // int maxArea = 0; // for(int i = 0; i < height.length; i++) { // for(int j = i+1; j < height.length; j++) { // int wide = j - i; // int area = wide * Math.min(height[i],height[j]); // maxArea = Math.max(maxArea,area); // } // } //2.左右对撞双指针 int left = 0, right = height.length-1; int maxArea = 0; while(left < right) { int wide = right - left; int area = wide * Math.min(height[left], height[right]); if(height[left] < height[right]) { left++; }else { right--; } maxArea = Math.max(maxArea, area); } return maxArea; } }
一、核心算法思路
采用左右对撞双指针,时间复杂度 O (n)
- 容器面积公式:
面积 = 宽度 × 两侧柱子较小高度,水位由更矮的柱子决定(短板效应); - 左指针 left 放在数组最左端,右指针 right 放在数组最右端,初始宽度最大;
- 计算当前两根柱子围成的面积,更新全局最大面积;
- 核心收缩规则:向内移动高度更小一侧的指针。若移动高柱子,宽度缩小、高度上限不变,面积只会更小;移动矮柱子才有机会遇到更高柱子,得到更大面积;
- 不断收缩区间,直到左右指针相遇,最终返回最大面积。
实例运行顺序演示
测试输入:height = [1,8,6,2,5,4,8,3,7]初始状态:left = 0,right = 8,maxArea = 0
| left | right | height[left] | height[right] | 宽度 | 当前面积 | maxArea | 操作 |
|---|---|---|---|---|---|---|---|
| 0 | 8 | 1 | 7 | 8 | 8 | 8 | 左边矮,left++ |
| 1 | 8 | 8 | 7 | 7 | 49 | 49 | 右边矮,right-- |
| 1 | 7 | 8 | 3 | 6 | 18 | 49 | 右边矮,right-- |
| 1 | 6 | 8 | 8 | 5 | 40 | 49 | 等高,right-- |
| 1 | 5 | 8 | 4 | 4 | 16 | 49 | 右边矮,right-- |
| 1 | 4 | 8 | 5 | 3 | 15 | 49 | 右边矮,right-- |
| 1 | 3 | 8 | 2 | 2 | 4 | 49 | 右边矮,right-- |
| 1 | 2 | 8 | 6 | 1 | 6 | 49 | 右边矮,right-- |
循环结束,left == right,最终最大面积:49
二、语法 & 概念理解困惑点整理
两种双指针区分 左右对撞双指针:left 从头、right 从尾,向中间靠拢(本题、两数之和 II); 快慢同向双指针:left、right 同时从起点向右遍历(283 移动零)。
三、踩坑清单
- 收缩指针逻辑写反 错误:移动更高一侧的柱子。宽度缩小,水位上限不变,不可能得到更大面积,算法失效。
- 循环条件写错 错误:
left <= right。指针相遇时宽度为 0,面积为 0,无计算意义,条件应为left < right。 - 暴力双层循环隐患 双重 for 枚举所有组合复杂度 O (n²),测试用例数据量大时会超时,面试不推荐。
- 等高时不知道移动哪边 左右柱子高度相等,left++ 或者 right-- 均可,不影响最终结果。
四、高频易混知识点
- 面积本质限制因素:容器储水高度由两根柱子矮者决定,不是高柱子;
- 双指针优化原理:利用面积数学规律,舍弃大量不可能更优的组合,把 O (n²) 优化到 O (n);
- 数组属于引用类型,本题只读取数组数值,不需要修改原数组。