Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
这道题的大致意思就是寻找可能组成最大桶的位置,最简单的就是暴力求解,这个是我想出来的方法(肯定也是一般人都能想到的方法),不过我网上看了其他人的解法,发现有一个双指针的解决方法。
大致思路就是使用指向数组头部和尾部的双向指针,不断收缩,在搜索过程中得到最优解。收缩策略是:如果 height[beg] < height[end] ,beg++,否者end–。 为什么这个策略可以求出最优值呢?网上的说法是:用两个指针从两端开始向中间靠拢,如果左端线段短于右端,那么左端右移,反之右端左移,知道左右两端移到中间重合,记录这个过程中每一次组成木桶的容积, 返回其中最大的。 我的理解是:按照这种策略收缩,才可能出现最优值,这个策略的主要就是提高最低木板的高度,每次搜索后的结果不一定都要比之前的要好,但是全局的最优解一定出现在某一次的搜索过程中。
代码如下:
public class Solution
{
/*
* 答案是有,用两个指针从两端开始向中间靠拢,如果左端线段短于右端,那么左端右移,
* 反之右端左移,知道左右两端移到中间重合,记录这个过程中每一次组成木桶的容积,
* 返回其中最大的。(想想这样为何合理?)
* 合理性解释:当左端线段L小于右端线段R时,我们把L右移,这时舍弃的是L与右端其他
* 线段(R-1, R-2, ...)组成的木桶,这些木桶是没必要判断的,因为这些木桶的容积
* 肯定都没有L和R组成的木桶容积大。
* */
public int maxArea(int[] height)
{
if(height==null || height.length<=1)
return 0;
int i=0,j=height.length-1,max=0;
while(i<j)
{
max=Math.max(max, (j-i)*Math.min(height[i], height[j]));
if(height[i]<height[j])
i++;
else
j--;
}
return max;
}
/*
* 暴力求解肯定超时
* */
public int maxAreaByBaoLi(int[] height)
{
if(height==null || height.length<=1)
return 0;
int maxArea=-1;
for(int i=0;i<height.length;i++)
{
for(int j=i+1;j<height.length;j++)
{
maxArea=Math.max(maxArea, (j-i)*(Math.min(height[j],height[i])));
}
}
return maxArea;
}
public static void main(String[] args)
{
Solution so=new Solution();
int []a={1,1};
System.out.println(so.maxArea(a));
}
}
下面的是C++的做法,就是使用双指针来计算最大值,这个使用了最短木桶理论, 这道题必须掌握。
代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution
{
public:
int maxArea(vector<int>& height)
{
int maxArea = 0;
int beg = 0, end = height.size() - 1;
while (beg < end)
{
maxArea = max(maxArea, (end-beg)*min(height[beg], height[end]));
if (height[beg] < height[end])
beg++;
else
end--;
}
return maxArea;
}
};