诱捕雨水隆起阵列

时间:2015-06-19 14:07:59

标签: java arrays algorithm

我在一篇试卷中经历了这个问题,并在答案书中找到了一个解决方案。我无法理解它背后的算法。谁能解释一下这个算法是如何工作的?

给定n个非负整数表示每个柱的宽度为1的高程图,计算下雨后能够捕获的水量。

例如,给定输入

[0,1,0,2,1,0,1,3,2,1,2,1] 

返回值为

6

根据答案书的解决方案就是这个

public class Solution {
    public int trap(int[] height) {
        if (height.length <=2 )
            return 0;
        int h = 0, sum = 0, i = 0, j = height.length - 1;
        while(i < j)
        {
            if ( height[i] < height[j] )
            {
                h = Math.max(h,height[i]);
                sum += h - height[i];
                i++;
            }
            else
            {   
                h = Math.max(h,height[j]);
                sum += h - height[j];
                j--;
            }
        }
        return sum;
    }
}

由于

7 个答案:

答案 0 :(得分:4)

我知道这可能不是以图形方式表示它的最佳方式,但您可以将情况想象如下图所示:

enter image description here

红色条纹是地形(根据示例的数组具有高程),蓝色条纹是可以“陷入”地形“山谷”的水。

简化,算法从左到右(如果左边较小)或从右到左(如果右边较小)循环所有条形,变量h存储每个步骤中找到的最大高度环路,因为水不能高于地形的最大高度,并且知道可以捕获多少水,它总结了水的高度(最大高度h)和特定点的地形高度,以获得实际的水量。

答案 1 :(得分:3)

WoDoSc非常适合绘制海拔和被困水的图表。水只能被困在两个较高的海拔之间。

我所做的是运行代码并输出结果,以便您可以看到如何计算捕获的水。代码从&#34; mountain&#34;的两端开始。范围。无论哪一端较低,都会靠近中心。

在两端高度相同的情况下,右端移动到更靠近中心的位置。你可以将左端靠近中心移动。

第一列是左侧高程的高度和索引。第二列是右侧高程的高度和索引。

第三列是最大最小高度。换句话说,左边或右边的最大高度,无论哪个最大值都较小。这个数字对于确定当地的水位很重要。

第四列是总和。

按照图表,您可以看到算法的工作原理。

0,0   1,11   0   0
1,1   1,11   1   0
1,1   2,10   1   0
0,2   2,10   1   1
2,3   2,10   2   1
2,3   1,9    2   2
2,3   2,8    2   2
2,3   3,7    2   2
1,4   3,7    2   3
0,5   3,7    2   5
1,6   3,7    2   6

6

这是代码。将print和println语句放在适当的位置可以帮助您理解代码的作用。

package com.ggl.testing;

public class RainWater implements Runnable {

    public static void main(String[] args) {
        new RainWater().run();
    }

    @Override
    public void run() {
        int[] height = { 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 };
        System.out.println(trap(height));
    }

    public int trap(int[] height) {
        if (height.length <= 2) {
            return 0;
        }

        int h = 0, sum = 0, i = 0, j = height.length - 1;

        while (i < j) {
            System.out.print(height[i] + "," + i + "   " + height[j] + "," + j
                    + "   ");

            if (height[i] < height[j]) {
                h = Math.max(h, height[i]);
                sum += h - height[i];
                i++;
            } else {
                h = Math.max(h, height[j]);
                sum += h - height[j];
                j--;
            }

            System.out.println(h + "   " + sum);
        }

        return sum;
    }

}

答案 2 :(得分:0)

该算法通过从左(i)和右(j)处理陆地来工作。 我和j是相互靠近中间的工作台。

h是一个变量,它跟踪到目前为止找到的最大高度,考虑到下方。

通过让i和j相互对等来处理土地。&#34;当我阅读代码时,我想象出两个假想的墙壁将水挤向中间,最低的墙壁朝向较高的墙壁移动。该算法继续总结水量。它使用h - height [x],因为水只能在两个墙之间的最低点内部被包含。因此,基本上它继续总结左右两侧的水量并减去水位,并通过更高的海拔块移位水。

可能更好的变量名称

  • leftWall而不是我
  • rightWall而不是j
  • waterMaxHeight代替 of h

答案 3 :(得分:0)

我认为上面的解决方案很难理解。我有一个简单的解决方案,它需要额外的空间和空间。 o(n)时间复杂度。

算法步骤

1.保持一个数组,其中包含当前元素右侧的所有元素的最大值。

2.从左侧保留一个变量max,其中包含当前元素左侧的所有元素的最大值。

3.从左边找到最小值&amp;右边的最大值,已经存在于数组中。

4.如果最小值大于数组中的当前值,则增加的差值大于ans&amp;添加与当前值和差异的差异从左边更新最大值。

&#13;
&#13;
import java.util.*;
import java.lang.*;
import java.io.*;


class Solution
{
	public static void main (String[] args) throws java.lang.Exception
	{
		int[] array= {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 };
		int[] arrayofmax=new int[array.length];
		int max=0;
		arrayofmax[array.length-1]=0;
		for(int x=array.length-1;x>0;x--){
		    if(max<array[x]){
		        max=array[x];
		    }
		    arrayofmax[x-1]=max;
		}
		int ans=0;
		int maxfromleft=0;
		
		for(int i=0;i<array.length-1;i++){
		    if(maxfromleft<array[i]){
		        maxfromleft=array[i];
		    }
		    int min=maxfromleft>arrayofmax[i+1]?arrayofmax[i+1]:maxfromleft;
		    if(min>array[i+1]){
		        ans+=min-array[i+1];
		        array[i+1]=min;
		    }
		}
		System.out.println(ans);
	}
}
&#13;
&#13;
&#13;

可能是我的算法与上面相同,但我认为这个实现很容易理解

答案 4 :(得分:0)

用Java解决陷阱雨水问题。

class Store
{
    static int arr[] = new int[]{0, 1, 0, 2, 2};

    // Method for maximum amount of water
    static int StoreWater(int n)
    {
         int max = 0;
         int f = 0;
         for (int i = 1; i < n; i++)
         {
             max = Math.max(arr[i], max);
             f += Math.max(arr[i], max) - arr[i];
         }
         return f;
    }

    public static void main(String[] args) 
    {
        System.out.println("Maximum water that can be accumulated is " + 
                                        findWater(arr.length));
    }
}

答案 5 :(得分:0)

这是解决集水问题的另一种简便方法。 O(1)空间和O(N)时间复杂度。
逻辑
->让我们从0索引循环到输入值的末尾。
->如果我们发现一堵墙大于或等于前一堵墙
->在名为prev_index的var中记录该墙的索引
->继续将前一堵墙的高度减去当前墙的高度(i th )添加到变量水中。
->具有一个临时变量,该变量也存储与水相同的值。
->循环直到最后,如果找不到任何大于或等于前一堵墙的墙,请退出。
->如果以上几点为真(即,如果prev_index <输入数组的大小),则从水中减去temp变量,并从输入数组的末尾循环至prev_index,并找到大于或等于前一个墙的墙(在这种情况下,是最后一堵墙从后向)

这里的概念是,如果右侧有较大的墙,则可以保留高度等于左侧较小的墙的水。
如果右侧没有较大的墙,则从左侧开始。您的左侧现在必须有一堵更大的墙。 您实际上要循环两次,所以O(2N),但渐近地为O(N),当然还有O(1)空间。

JAVA代码在这里:

class WaterTrap 
{ 

    public static void waterTrappingO1SpaceOnTime(){
        int arr[] = {1,2,3,2,1,0}; // answer = 14
        int size = arr.length-1;
        int prev = arr[0];  //Let first element be stored as previous, we shall loop from index 1
        int prev_index = 0; //We need to store previous wall's index
        int water = 0;
        int temp = 0;   //temp will store water until a larger wall is found. If there are no larger walls, we shall delete temp value from water
        for(int i=1; i<= size; i++){
            if(arr[i] >= prev){     // If current wall is taller then previous wall, make current wall as the previous wall, and its index as previous wall's index for the subsequent loops
                prev = arr[i];
                prev_index = i;
                temp = 0;   //because larger or same height wall is found
            } else {
                water += prev - arr[i]; //Since current wall is shorter then previous, we subtract previous wall height from current wall height and add to water
                temp += prev - arr[i];  // Store same value in temp as well, if we dont find larger wall, we will subtract temp from water
            }
        }
// If the last wall was larger than or equal to the previous wall, then prev_index would be equal to size of the array (last element)

// If we didn't find a wall greater than or equal to the previous wall from the left, then prev_index must be less than index of last element
        if(prev_index < size){
            water -= temp; //Temp would've stored the water collected from previous largest wall till the end of array if no larger wall was found. So it has excess water. Delete that from 'water' var 
            prev = arr[size];   // We start from the end of the array, so previous should be assigned to the last element. 
            for(int i=size; i>= prev_index; i--){ //Loop from end of array up to the 'previous index' which would contain the "largest wall from the left"
                if(arr[i] >= prev){ //Right end wall will be definitely smaller than the 'previous index' wall 
                    prev = arr[i];
                } else {
                    water += prev - arr[i];
                }
            }

        }
        System.out.println("MAX WATER === " + water);
    }
 public static void main(String[] args)  { 
          waterTrappingO1SpaceOnTime();
   } 

}

答案 6 :(得分:0)

Algorithm: 
1.Create two array left and right of size n. create a variable max_ = INT_MIN.
2.Run one loop from start to end. In each iteration update max_ as max_ = max(max_, arr[i]) and also assign left[i] = max_
3.Update max_ = INT_MIN.
4.Run another loop from end to start. In each iteration update max_ as max_ = max(max_, arr[i]) and also assign right[i] = max_
5.Traverse the array from start to end.
6.The amount of water that will be stored in this column is min(a,b) – array[i],(where a = left[i] and b = right[i]) add this value to total amount of water stored
7.Print the total amount of water stored.

代码:

/*** Theta(n) Time COmplexity ***/
        static int trappingRainWater(int ar[],int n)
        {
            int res=0;
            int lmaxArray[]=new int[n];
            int rmaxArray[]=new int[n];
            lmaxArray[0]=ar[0];
            for(int j=1;j<n;j++)
            {
                lmaxArray[j]=Math.max(lmaxArray[j-1], ar[j]);
            }
            rmaxArray[n-1]=ar[n-1];
            for(int j=n-2;j>=0;j--)
            {
                rmaxArray[j]=Math.max(rmaxArray[j+1], ar[j]);
            }
            for(int i=1;i<n-1;i++)
            {
                res=res+(Math.min(lmaxArray[i], rmaxArray[i])-ar[i]);
            }
            return res;
        }