初始思路
这个题我一看到的时候感觉不会很难,然后看了一会有了解题思路:肯定是两个指针分别从首部和尾部往中间靠拢,然后找出其中的最大值,关键就是怎么移动这两个指针,或者说这两个指针是按照什么规则来改变。然后又拿了给的例子,发现既然求最大,那两边的指针谁的下一步最大,就应该先移动谁,即
if ((height[high-1] - height[high]) >= (height[low+1] - height[low])) {
high--; //若右边增加的比较多(减少的比较少),则右边指针移动
} else {
low++; //否则左边指针移动
}
但是发现不对劲啊,虽然给的例子结果是对的,但测试用例是错的,于是我陷入了沉思,开始回忆自己刚才在干什么,要干什么,从哪里来,到哪里去…最后我发现了,那个思路就是错的,即使有一边增长的比较快,但如果另一边一直都是1,那再快总的面积也没有增加,相反因为指针不断移动,会导致面积逐渐变小,所以这个关键点在于两个指针所指的值的最小值,也就是木桶效应。于是重新审视,有了以下思路。
正确思路
这个过程中,面积一直是由两个指针所指的值中最小的那个决定的,假如现在两个指针在各自的初始位置,此时的最大面积就是初始围成的面积。然后左边的值较小,则移动左边的指针向前,这时候左边指针指向的值会有三种变化情况:
- 值变的更小了。那么此时面积会更小,所以最大值不变
- 值不变。那么此时面积会减1,因为两个指针的距离减了1,所以最大值不变。
- 值变大了。当然这种情况可能导致面积变大或变小,而且有可能会更新最大值。
总之,这时候就是应该移动左边的值,才有可能使最大值更新。相反,如果左边值较小时移动右边指针,则不管右边的值变大还是变小,面积都会减小,因为面积总是(两者原始间隔-1)*左边值。所以正确的移动策略是更新较小值那边的指针。代码如下:
class Solution {
public int maxArea(int[] height) {
int result = 0;int i = 0, j = height.length - 1;while (i < j) {
int cur = (j-i) * Integer.min(height[i], height[j]);result = cur > result ? cur : result;if (height[i] >= height[j]) {
//左边高则移动右边指针--j;} else {
//右边高则移动左边指针++i;}}return result;}
}
当然还有一种暴力的方法,就是求出每一种可能,然后找最大值,代码如下:
class Solution {
public int maxArea(int[] height) {
int result = 0;for (int i = 0; i < height.length; ++i) {
for (int j = i+1; j < height.length; ++j) {
int cur = (j-i) * Integer.min(height[i], height[j]);if (result < cur) {
result = cur;}}}return result;}
}