题目
给定一个长度为 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。
来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
代码
public class Leetcode11 {
// 暴力
@Deprecated
public int maxArea0(int[] height) {
int max = 0;
for (int i = 0; i < height.length - 1; i++) {
for (int j = i + 1; j < height.length; j++) {
max = Math.max(max, (j - i) * Math.min(height[i], height[j]));
}
}
return max;
}
// 双指针
public int maxArea(int[] height) {
int max = 0;
int left = 0;
int right = height.length - 1;
while (right > left) {
max = Math.max(max, (right - left) * Math.min(height[right], height[left]));
if (height[right] > height[left]) {
left++;
} else {
right--;
}
}
return max;
}
}
解释
法一:暴力遍历, 两个for循环去做;比较所有场景,记录下最大的那个。方法很简单清晰,但是复杂度过高,case无法全部过。仔细分析下这种方法,其实做了许多无用功,比如我们每次移动的都是右边的指针,当有一种情况,height[i]<height[j],这种时候无论怎么移动j,面积都不会变大了,因为此时的面积受限于值比较小的那个,即height[i]。所以其实用两层for循环的话,也可以加个判断,当height[i]<height[j]时,就直接跳到i+1的循环,不用移动j了
法二:双指针, 基于上面分析的,可以去掉一部分无用功;但是其实可以做的更彻底,去两个指针,left和right;从一开始就比较两端的大小,哪个小哪个就往中间移动,直到两者重合,期间记录下的最大的值就是我们需要的。
总结
这是非常重要、典型的双指针题目;第一次做确实无法想到这种方法,其实理解双指针就是一个分析去除无用功的逻辑。多做题总结即可