题目描述
给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
分析
如果使用暴力搜索,
时间复杂度:O(n^2),计算所有种高度组合的面积。
空间复杂度:O(1),使用恒定的额外空间。
使用双指针搜索:
我们在由线段长度构成的数组中使用两个指针,一个放在开始,一个置于末尾。 此外,我们会使用变量 maxarea 来持续存储到目前为止所获得的最大面积。 在每一步中,我们会找出指针所指向的两条线段形成的区域,更新 maxarea,并将指向较短线段的指针向较长线段那端移动一步。
代码如下:
class Solution {
public:
int maxArea(vector<int>& height) {
int size = height.size();
int maxVal = 0;
int i,j;
i = 0;
j = size-1;
while (i<j) {
int minVal = min(height[i],height[j]);
maxVal = max(minVal*(j-i),maxVal);
if(height[i]< height[j])
i++;
else
j--;
}
return maxVal;
}
};
那么,为什么这种双指针搜索不会错过最优解呢?
我们从最开始,i=0,j=n-1开始分析,res表示容器的体积,一共两种情况:
(1)第一根高度比最后一根高度要矮,这个时候要把当前的容积存下来,并把左指针右移一位 ,这个时候之后就不用考虑第一根柱子了,为什么呢?
因为固定左侧指针为第一根柱子不动时,对于第一根柱子来说,另一根柱子选择最后一根柱子已经是使容器体积最大,也即res最大的方案了。所以我们把这个容积res=(n-1)*height[0]存下来之后,就不需要考虑第一根柱子了,不像暴力搜索中,两层循环。这又是为什么呢?我们也分两种情况考虑。
(a)如果选取的右侧柱子比第一根高,那么不论右侧柱子是哪一根,容器的高度h肯定取较短的那一侧高度,也就是第一根柱子高度height[0],接下来只需要看容器的宽度,也就是(j-i)的大小就好了,显然n-1是最大的宽度了,所以此时右指针是n-1是最优选择;(b)如果选取的右侧柱子比第一根矮,那么h<height[0]还小,而且容器的宽度比n-1也小,所以容积肯定也比(n-1)*height[0]小了。
所以第一种情况下,最大的容积res=(n-1)*height[0],把这个值保存下来,想要看还有没有比这个res还大的情况,第一根柱子就不用考虑了,故把i加一,从第二根柱子开始重复这个比较过程;
(2)第一根高度比最后一根高度要高:那么跟上面这种情况类似,我们从后往前看,从最后一根柱子的视角来看,另一根柱子选择第一根柱子是使得res最大的选择,接下来把res保存下来,把j减一,就可以不用考虑最后一根柱子了。
从而,可以实现时间复杂度为O(n)的算法了,即只要一次遍历即可。
---------------------
作者:FutureFrancis
来源:CSDN
原文:https://blog.csdn.net/futurefrancis/article/details/88603089
版权声明:本文为博主原创文章,转载请附上博文链接!