题目:
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.
总结:我们必须使用垂直的两条线中较短的一条线作为高和两点之间的距离作为长来最大化矩形面积。
方法1:(暴力方法)
尝试各种可能,从而找到最大的矩形,我一开始也是这么想的,只能想到这一点,结果超时(Time Limit Exceeded)。时间复杂度是O(n2),空间复杂度O(1),参考代码如下所示:
class Solution { public: int maxArea(vector<int>& height) { int i,j; int bigger; int maxarea=0; int area; for(i=0;i<height.size();i++){ for(j=i+1;j<height.size();j++){ bigger=height[i]>height[j]?height[j]:height[i]; area=bigger*(j-i); if(area>maxarea) maxarea=area; } } return maxarea; } };
方法2:
想要围成的矩形面积最大,一种直观的感觉是两个点相隔的距离尽量远,并且两个点的高度都很高。我们采用两个指针,一个指针指向数组的头部,另一个指针指向数组的尾部。总是指向较低高度的指针向数组内部移动,因为这样可以获得更高的较低高度,如果当前矩形的面积大于最大面积,则更新最大面积。时间复杂度为O(n),Accepted。
class Solution { public: int maxArea(vector<int>& height) { int *head,*tail; int maxarea=0,area; head=&height[0]; tail=&height[height.size()-1]; while(head!=tail){ area=(tail-head)*(*head>*tail?*tail:*head); if(area>maxarea) maxarea=area; if(*head>*tail) tail--; else head++; } return maxarea; } };
一个更加直观的描述方式是通过矩阵的形式进行描述:
画出一个矩阵,行代表第一条线,列代表第二条线,假如n=6。如下图所示:
图中的x表示我们不需要计算的面积,这种情况分为两种:
(1) 两条线重合时,比如(2,2),第一条线在2上,第二条线也在2上
(2) 有重复计算,比如(2,6)和(6,2)是一样的
我们从(1,6)开始计算,用o表示,如果左边的线的高度小于右边的线,那么从6往左边所有的都不用算了,一定比(1,6)小,用--表示,如上图所示。
现在我们移动到(2,6),如果右边的线是较短的,那么从2往右边所有的都不用算了,一定比(2,6)小,如下图所示:
现在我们移动到(2,5),按照这种移动方式,我们仅需要移动n-1次,即能找到最大值,时间复杂度为O(n)。