第一篇,记录自己的学习经历!(算法,装水问题)

  本人的第一篇blog,首先介绍一下本人资料。本人今年23岁,美帝程序员一名,可是现在H1B还遥遥无期,恶心的公司今年不给办,于是本人一心想着跳槽,开始了刷题之旅。开始刷题的过程是值得记录的,从这之中再一次认识到自己的基础底子之差!有种学海无涯,回头是岸的感觉。但是!人不奋斗!还有什么意义呢,天天刷刷微博?朋友圈?其实内心空虚寂寞得厉害,anyway 今天开始要记录本人刷题过程。

  第一道题,装水问题,从别人的blog看来的,自己看了看,还是很巧妙的一道题。分享一下,写下来也供自己以后参考。


 

 

题目描述:

看下面这个图片,在这个图片里我们有不同高度的墙。这个图片由一个整数数组所代表,数组中每个数是墙的高度。上边的图可以表示为数组[2,5,1,2,3,4,7,7,6], 假如开始下雨了,那么墙之间的水坑能够装多少水呢?”

以1×1的方块为单位计算容积。所以,在上边的图中下标为1以左的都会漏掉。下标7以右的也会漏掉。剩下的只有在1和6之间的一坑水,容积是10。如下图所示。

分析:

原文作者最初想法是用极大值考虑,也就是说找到下标2的左右两个极大值,但是这个做法最后作者意识到是错误的。比如下面的情况就不对:

看看这个输入:

第一篇,记录自己的学习经历!(算法,装水问题)_第1张图片

如果答案计算的是极大值之间的水,就像这样。

第一篇,记录自己的学习经历!(算法,装水问题)_第2张图片

但是答案应该是在两个高塔之间只有一池水:

第一篇,记录自己的学习经历!(算法,装水问题)_第3张图片

以上题为例:

1)遍历数组找到数组的最大值,记录下来。

2)进行第二遍遍历,从数为2开始,记录volume为0;

3)2->5,此时左边小于右边,谁都会流失,所以volume还是为0,左边最大又2变为5;

4)5->1,此时右边小于左边,又知最右边还有更大的7,所以这一定能存贮水源,故volume=5-1=4;

5)5->3,同上,volume=5-3=2,再加上之前的此时volume=2+4=6;

6)5->1,同上,volume=(5-1)+6=10;

7)一次类推,直到7为止,然后从右边开始向7推进,相同的步骤。

8)最后得出结果。

但在推进的结果中,发现,其实有更加优化的解法。不需要第一遍遍历找出最大值,直接将数组从两边向中间推进即可。

思路:

将数组的起始index和最终index赋给两个变量(left,right),然后左右两端遍历,一开始比较最左和最后端的值,选出较小的那一端,再让较小的值与他相邻的值比较(左端则比较arr[left]与arr[left+1],右端则比较arr[right]与arr[right-1])若小于则替换,volume为0。大于则计算出volume,毕竟另一端有更大的值,则一定能蓄水,这样显得有恃无恐,然后再进行下一次的遍历。

附上代码:

public int getVolume(int[] arr){

   int left=0,right=arr.length-1;

   int max_l=arr[left],max_r=arr[right];

   int volume=0;

   while(left

        if(max_l

         {      

                 left=left+1;

                 if(arr[left]>max_l)

                       max_l=arr[left];

                 else

                       volume=volume+(max_l-arr[left]);

          }

          else

          {

                 right=right-1;

                 if(arr[right]>max_r)

                      max_r=arr[right];

                 else

                      volume=volume+(max_r-arr[right]);

           }

   }

   return volume;

}

  

你可能感兴趣的:(算法)