zoukankan      html  css  js  c++  java
  • Trapping Rain Water

           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

  • 相关阅读:
    IntelliJ IDEA生成 Serializable 序列化 UID 的快捷键
    spring boot rabbitmq 多MQ配置 自动 创建 队列 RPC
    JAVA使用并行流(ParallelStream)时要注意的一些问题
    深入浅出Stream和parallelStream
    JAVA8 十大新特性详解
    redis客户端连接,最大连接数查询与设置
    如何在Java 8中愉快地处理日期和时间
    Jenkins:使用Git Parameter插件实现tag或分支的选择性构建
    Java正确获取客户端真实IP方法整理
    redis问题接囧办法及经验
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247137.html
Copyright © 2011-2022 走看看