ps:本文章仅用来记录日常学习的所思所想,各位看到可取之处也可纳为己用,说的不对的地方还请多多指教。
1.题目描述
11.盛最多水的容器(中等)
2.题目分析
首先理解题目永远最重要。
给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, )
。找出其中的两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。
根据这题意以及图中的蓝色部分,我们不难理解出这题是要咱们求最大面积,接下来就是想想小学的时候学的长方形面积公式:
面积=长*宽
里面的的宽不难想到就对应着height[i]
然后长自然就是两条“宽”的下标之差啦。
所以根据题目咱们还是不难想到用双指针做的(毕竟这题就属于双指针板块)。
双指针:
class Solution {
public int maxArea(int[] height) {
int result = 0;
int i = 0;
int j = height.length - 1;
while(i < j){
int area = Math.min(height[i], height[j]) * (j - i);
result = Math.max(result, area);
if(height[i] <= height[j]){
i++;
}else{
j--;
}
}
return result;
}
}
接下来一步步解释一下为什么这么做。
int result = 0;
int i = 0;
int j = height.length - 1;
定义的这三个变量分别是我们要返回的面积值result以及我们的前后两个指针i,j。
while(i < j){
int area = Math.min(height[i], height[j]) * (j - i);
result = Math.max(result, area);
if(height[i] <= height[j]){
i++;
}else{
j--;
}
}
重点就在这个循环中,因为我们要求面积最大,所以 i,j分别在数组的最前面跟最后面,这样做会先设定长方形的“长”是最长的,于是我们只需要考虑宽的长度。
因为我们并不明确要循环多少次,所以我们选择while循环,当i跟j相遇,也就是i等于或者大于j了就已经没有必要循环下去了,所以是while(i<j)。
int area = Math.min(height[i], height[j]) * (j - i);
result = Math.max(result, area);
这里用到Math的min跟max方法, 因为根据水桶效应,决定能盛多少水的是最短的那块板,所以我们用min()来找出最短的板来算面积。然后再跟result比大小,大的赋值给result,这里很好理解。
if(height[i] <= height[j]){
i++;
}else{
j--;
}
这里是整道题最关键的地方,我们应该如何来保留"宽"的最大值?当然是一次只移动小的那一方的指针,保留大的“宽”来保留找最大面积的可能性。
3.总结
1.做题不能只拘泥于题目,要跟出题人玩脑筋,头脑风暴尽量想得全面。
2.善用java的api如Math、ArrayList等可以简化代码。