leetcode 11 Container With Most Water

来源:互联网 发布:一号店软件吧 编辑:程序博客网 时间:2024/05/01 22:05

Container With Most Water
Total Accepted: 48739 Total Submissions: 153072

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.

这道题意思很明确,就是给出一些点,然后将这些点与x轴做垂线,这样就形成许多条垂线段,把这些垂线段想象成木桶的桶壁,x轴想象成木桶的桶底,题目要求在其中选出两个桶壁,使得形成的木桶装水的体积最大。

这道题最直观的想法就是搜索所有可能的桶壁的组合,找出使得装水体积最大的组合。但这样一来,就是O(n2)的。提交测试果然超时,挂在一组有15000个点的测试用例上。后来尝试添加一些判断条件,减少搜索次数,但是效果甚微。后来看小Discuss,原帖地址:https://leetcode.com/discuss/53305/a-fast-and-easy-understand-cpp-solution 发现原来有一种O(n)的方法。只用扫一遍,就可以找出最大体积。

该方法的主要过程是这样的,一头一尾用两个指针,计算两者形成的木桶的装水体积。然后选两者较小的一个,把它往靠近中间位置移一格,如果,新的桶壁高度不如之前移动的桶壁,那么就再往中间位置移一格,重复这个过程,直到新的桶壁高度高于移动的桶壁。然后再计算新形成的木桶的装水的体积。然后再选择两者较小的一个,把它往靠近中间位置移一格,重复上面的过程,直到两个指针重合。此时的最大体积,就是我们要求的所有可能组合中的最大体积。

我们用一个例子来说明这个过程:
这里写图片描述
总共6块桶壁,那么我们首先计算首尾两个桶壁形成的木桶的装水体积
这里写图片描述
然后我们比较两个桶壁的大小,找出小的一个,然后向中间移动一格。此时我们要移动的就是指向6号桶壁的指针,让它指向5号桶壁,这样一次移动其实就排除了2-6,3-6, 4-6,5-6四种组合,因为这四种组合不可能体积大于1-6. 原因很简单,首先底边长度小于1-6组合,其次由于都和6号桶壁组合所以高度最多为4(即6号桶壁的高度)而1-6组合的高度就是4,所以乘起来的结果必然小于1-6组合,所以直接淘汰掉。下面比较新指向的5号桶壁和6号桶壁的高度,如果5号桶壁的高度低于等于6号桶壁的高度那么5号桶壁淘汰,因为所有与5号桶壁的组合都有一个对应的与6号桶壁的组合,并且底边比其长1。例如:1-5对应1-6, 2-5对应2-6, 3-5对应3-6… …但在高度上1-5组合为min(h1,h5),1-6组合为min(h1,h6),而h5h6, 所以min(h1,h5)min(h1,h6),因此,对应的6号桶壁的组合装水体积更大,对于2-5,3-5等也是同样的道理,都会小于等于2-6,3-6等。因此5号桶壁的组合不会产生比6号桶壁的组合产生更多的装水体积。所以5号桶壁被淘汰。但在我们的例子中,5号桶壁的高度高于6号桶壁的高度,所以就有可能产生更多的装水体积,所以不能直接淘汰,需要计算体积。之前最大的1-6组合体积为20,现在1-5组合的体积也为20. 所以最大体积不变,接着我们重复上面的过程,在找出1号桶壁和5号桶壁中高度较小的一个,然后将它向中间移一格,于是指向1号桶壁的指针指向了2号桶壁,这个过程排除了1-2,1-3,1-4这三种组合,6号桶壁因为之前已经被淘汰了,所以1-6之前就被排除了,排除1-2,1-3,1-4的理由和之前排除2-6,3-6, 4-6,5-6是一样的道理,不再赘述。现在1号桶壁和6号桶壁都被淘汰了,现在比较2号桶壁与之前的桶壁(1号桶壁)的高度,发现2号桶壁比1号桶壁高度更低,那么2号桶壁直接就淘汰了,原因我之前比较5号和6号桶壁时就介绍了。现在1,2,6号桶壁都被淘汰了。那么我们把指向2号桶壁的指针继续向中间移指向3号桶,比较3号桶和之前的桶壁(1号桶壁)的高度,发现3号桶壁更高,所以重新计算体积,体积为12,因此最大体积仍为20。值得注意的一点是之前的桶壁不是2号桶壁,而是之前进行计算的1号桶壁,因为当我们重新计算体积时,才会更新桶壁,2号桶壁直接被淘汰了,所以没有进行计算,因此不算作之前的桶壁。

接下来比较3号桶壁和5号桶壁的高度,发现5号桶壁较矮,所以指向5号桶壁的指针改指向4号桶壁,5号桶壁被淘汰,对应的4-5组合被排除,比较4号桶壁和之前的桶壁(即5号桶壁),4号桶壁比较高,所以重新计算体积,体积为7. 因此最大体积仍为20,然后比较3号桶壁和4号桶壁,发现3号桶壁较矮,因此移动指向3号桶壁的指针指向4号桶壁,3号桶壁被淘汰(注意:我所说的淘汰是指它没有机会产生比当前最大值更大的体积)。此时首尾两个指针都指向4号桶壁,指针重合,因此退出循环。当前的最大体积就是所有可能组合的最大体积。

下面是程序的完整代码:

#include <iostream>#include <stdlib.h>#include <stdio.h>using namespace std;int maxArea(int* height, int heightSize) {    if(heightSize < 2)        return 0;    int indexl = 0, indexr = heightSize - 1;    int max = 0, tmpArea = 0;    int currentHeight = 0;    while(indexl < indexr)    {        if(height[indexl] < height[indexr])        {            tmpArea = height[indexl] * (indexr - indexl);            max = max < tmpArea ? tmpArea : max;            currentHeight = height[indexl];            indexl++;            while(indexl < indexr && height[indexl] <= currentHeight)            {                indexl++;            }        }        else        {            tmpArea = height[indexr] * (indexr - indexl);            max = max < tmpArea ? tmpArea : max;            currentHeight = height[indexr];            indexr--;            while(indexl < indexr && height[indexr] <= currentHeight)            {                indexr--;            }        }    }    return max;}int main(){    int heightSize;    cout<<"Input the heightSize:"<<endl;    cin>>heightSize;    int *height = (int*)malloc(sizeof(int) * heightSize);    for(int i = 0; i < heightSize; i++)        scanf("%d,", &height[i]);    cout<<maxArea(height, heightSize)<<endl;    return 0;}
0 0
原创粉丝点击