Trapping Rain Water

来源:互联网 发布:无法连接到这个网络 编辑:程序博客网 时间:2024/05/27 16:42

       Given n non-negative integers representing an elevation map where the width of each bar is 1,compute how much water it is able to trap after raining.

       For example, 

Given [0,1,0,2,1,0,1,3,2,1,2,1],return 6.

 

       思路:每个数代表了柱子的高度,求总的成水量。最初的思路是这样的:首先找到最高的柱子,然后找第二高的柱子,它们之间的成水量,就是第二高的柱子的高度,乘以它们之间的距离,然后减去它们中间的所有柱子的面积(高度)。这两根柱子就形成了一个边界,然后依次去找第三高,第四高...的柱子,分别求出它们与边界之间的成水量即可。

       既然要从大到小寻找柱子,那么就得排序,按照高度从大到小排序,主要是记录这些柱子的索引。代码如下:

typedef struct{    int value;    int index;}Node;     //辅助结构,记录高度和索引,按照高度从大到小排序 #define min(x,y)  (((x)<(y))?(x):(y)) void swapnode(Node*n1, Node *n2){    Node tmp;    tmp.value = n1->value;    tmp.index = n1->index;     n1->value = n2->value;    n1->index = n2->index;     n2->value = tmp.value;    n2->index = tmp.index;}//下面是对Node结构的快速排序,从大到小。int partition(Node*nset, int left, int right){    int key = nset[right].value;    int i = left-1;    int j;    for(j = left; j <right; j++)    {        if(nset[j].value >key)        {            i++;            swapnode(nset+i,nset+j);        }    }    swapnode(nset+i+1,nset+right);    return i+1;} void qsortnode(Node*nset, int left, int right){    int q = -1;    if(left < right)    {        q = partition(nset,left, right);        qsortnode(nset, left,q-1);        qsortnode(nset, q+1,right);    }}//主函数int trap(int*height, int heightSize){    if(heightSize <= 2)return0;       Node *vi = calloc(heightSize,sizeof(Node));    int i;    int sum = 0;    int left, right, minvalue;     //首先对辅助结构进行排序,主要是得到他们的索引顺序    for(i = 0; i <heightSize; i++)    {        vi[i].value = height[i];        vi[i].index = i;    }     qsortnode(vi, 0, heightSize-1);     //以最高的柱子为边界    left = right = vi[0].index;    sum = 0;       for(i = 1; i <heightSize; i++)    {        int index = vi[i].index;        int value = vi[i].value;         /*如果该柱子已经处于边界中,则需减去他们的面积,因为在得到边界的时候,已经将这些柱子计算在内了。*/        if(index < right &&index > left)        {            sum -= value;        }        /*扩展左边界,计算边界内的盛水总面积,包括中间柱子的面积*/        else if(index <left)        {            sum += height[index]* (left-index-1);            left = index;        }        /*扩展右边界,计算边界内的盛水总面积,包括中间柱子的面积*/        else if(index >right)        {            sum += height[index]* (index-right-1);            right = index;        }    }       return sum;}

        上面的算法不是最优的,时间复杂度为O(nlogn),空间复杂度为O(n)。leetcode上的测试时间是8ms。时间和空间主要浪费在排序上了,其实可以不用排序的。思路如下:

        首先找到最高的柱子,以它为隔板,将整个数组分成左右两部分。左半部分中,从左到右依次扫描,因为隔板的存在,所以只要左边的柱子比右边高,则高度差就可以盛水。右半部分同理。这种算法的时间复杂度为O(n),空间复杂度为O(1)。leetcode上的测试时间是4ms。代码如下:

int trap_nb(int*height, int heightSize){    int i;    int sum = 0;    int maxindex = 0;    int prehight = 0;    //找最高柱子的索引    for(i = 1; i <heightSize; i++)    {        if(height[i] >height[maxindex])        {            maxindex = i;        }    }    //从左到右扫描,计算高度差    prehight = 0;    for(i = 0; i <maxindex; i++)    {        if(height[i] >prehight)        {            prehight = height[i];        }        sum += prehight - height[i];    }    //从右到左扫描,计算高度差    prehight = 0;    for(i = heightSize-1;i > maxindex; i--)    {        if(height[i]> prehight)        {            prehight = height[i];        }        sum += prehight - height[i];    }    return sum;}

 

        参考: https://github.com/haoel/leetcode/blob/master/algorithms/trappingRainWater/trappingRainWater.cpp

0 0
原创粉丝点击