1.直接思维法
class Solution {
public int maxArea(int[] height) {
if(height==null||height.length==0||height.length==1){
return 0;
}
int max=0;
for(int j=0;j<height.length;j++)//起点
{
for(int i=1;i<=height.length-1;i++){//控制底边的长度。
if(j+i<height.length){
int water = Math.min(height[j],height[j+i])*i;
if(max<water)
max = water;
}else
break;
}
}
return max;
}
}
一次就accept,但是效率感人:
毫无疑问,时间复杂度达到了O(N2)
2.动态规划法
根据清华大佬的说法,动态规划步骤在于:
- 1、确定状态
确定状态的关键在于:
找出最后一步,然后由最后的一步得出子问题的结构。
这个问题里面,最后的结果就是我们找到了使得盛得的水最多的两个端点:ai,aj,水量res。那么她的上一步是什么?上一步必定是在寻找这两个端点或者其中之一的端点,也就是说:也就是说会出现一个下标移动。于是子问题就有了。我们找当前的ai,aj,需要找到上一次的某两个端点a1,a2,她的盛水量不是最大的。(如何知道不是最大的,我们需要一个记录量,记录当前的最大量,即res)才会出现下标的移动。
则有如下的结果:
-
(a[i],a[j])<-(a[i-1],a[j]),if(a[i-1]<a[j])
-
(a[i],a[j])<-(a[i],a[j+1]),if(a[i]>a[j+1])
于是我们可以推出,当计算到a[i][j]时,我们算的当前的最大量为res,接下来,我们无法确定res是否为全局最大,因为我们还没有计算完可能结果。我们还要计算其他的端点组成的值。于是我们需要将下标移动,即怎么移动呢?当height[i]<height[j]则移动的下标应该是i,谁小移动谁,因为:
因为,由于容纳的水量是由
两个指针指向的数字中较小值 * 指针之间的距离
决定的。如果我们移动数字较大的那个指针,那么前者「两个指针指向的数字中较小值」不会增加,后者「指针之间的距离」会减小,那么这个乘积会减小。那么不符合我们要找最大的量的需求。因此,我们移动数字较大的那个指针是不合理的。因此,我们移动 数字较小的那个指针。
于是定义状态,开数组表示。具体还要考虑所开数组的维度和其大小。
- 2、递推方程
res = min(res,(j-i)*min(height[i],height[j])); - 3、初始条件和边界情况
初始条件就是我们有这个可能,但是计算不出来,同时又是需要用来递推的。
这道题没有边界。初始条件:需要两个端点才能盛水。于是height.length<=1,return -1; - 4、计算顺序,即用到该值时,其需要已经推出。这里没有要考虑的
只有做到上面的四步,才开始写代码。
class Solution {
public int maxArea(int[] height) {
if(height.length<=1)
return -1;
int i = 0,j=height.length-1,res = 0;
while(i<j){
int min = Math.min(height[i],height[j]);
res = Math.max(res,(j-i)*min);
if(height[i]<height[j]){
i++;
}else j--;
}
return res;
}
}
参考官方题解(双指针法)。这是我第一次真正的感觉自己摸到了动态规划的门。