捕获雨水海拔是阵列

Posted

技术标签:

【中文标题】捕获雨水海拔是阵列【英文标题】:trapping rain water elevations is array 【发布时间】:2015-06-19 14:07:59 【问题描述】:

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

给定 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;
    

谢谢

【问题讨论】:

什么不清楚?该算法做什么?为什么该算法有效? The Maximum Volume of Trapped Rain Water in 3D的可能重复 【参考方案1】:

我知道用图形表示可能不是最好的方式,但你可以把情况想象成下图:

红色条是地形(根据您的示例阵列具有高程),蓝色条是可以“困”在地形“山谷”中的水。

简化,算法从左到右(如果左更小)或从右到左(如果右更小)循环所有条形,变量h存储在每个步骤中找到的最大高度循环,因为水不能高于地形的最大高度,并且要知道可以捕获多少水,它将水的高度(最大高度h)与地形的高度之间的差异相加在特定点上,获取实际的水量。

【讨论】:

从这张图中的主要观点是,被填满的地形单调上升直到达到最大值,然后从那里单调下降。【参考方案2】:

WoDoSc 很好地绘制了海拔和积水的图表。水只能被困在两个更高的海拔之间。

我所做的是运行代码并输出结果,以便您了解如何计算滞留水。代码从“山”范围的两端开始。越低的一端越靠近中心。

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

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

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

第四列是总和。

跟随图表,你可以看到算法是如何工作的。

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;
    


【讨论】:

你太好了,但你能解释一下算法的逻辑吗?我正在考虑计算最高海拔的运行总和,然后计算最高海拔的运行总和,但方向相反。我不确定上述解决方案如何实现这一目标? @anonymous:看看增强解释是否更好。【参考方案3】:

该算法通过从左侧 (i) 和右侧 (j) 处理土地来工作。 i 和 j 是计数器,它们在接近土地中间时相互靠近。

h 是一个变量,用于跟踪迄今为止找到的最大高度(考虑到下侧)。

土地是通过让 i 和 j “相互接近”来处理的。当我阅读代码时,我想象了两堵假想的墙将水挤向中间,最低的墙向更高的墙移动。该算法继续对水的体积求和。它使用 h - height[x] 因为水只能包含在两堵墙之间的最低点内。所以本质上它会继续从左侧和右侧总结水的体积,并减去高海拔块排出的水。

也许更好的变量名会是

leftWall 而不是 i rightWall 而不是 j waterMaxHeight 代替 的 h

【讨论】:

【参考方案4】:

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

算法步骤

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

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

3.找到数组中已经存在的左侧最大值和右侧最大值的最小值。

4.如果最小值大于数组中的当前值,则在 ans 中添加比的差异并添加与当前值的差异并从左侧更新最大值。

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);
	

可能是我的算法和上面的一样,但我认为这个实现很容易理解

【讨论】:

【参考方案5】:

用 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));
    

【讨论】:

OP 正在寻找解决方案的解释。这不是一个相关的答案。另外,用你的代码 sn-p 添加一个解释。【参考方案6】:

这是解决积水问题的一种不同且简单的方法。 O(1) 空间和 O(N) 时间复杂度。 逻辑: -> 让我们从索引 0 循环到输入值的末尾。 -> 如果我们发现一堵墙大于或等于前一堵墙 -> 在名为 prev_index 的 var 中记下该墙的索引 -> 继续将先前墙的高度减去当前(ith)墙添加到变量水。 -> 有一个临时变量,它也存储与水相同的值。 -> 循环到最后,如果没有找到大于或等于前一堵墙的墙,则退出。 -> 如果以上点为真(即如果 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();
    


【讨论】:

【参考方案7】:
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;
        

【讨论】:

以上是关于捕获雨水海拔是阵列的主要内容,如果未能解决你的问题,请参考以下文章

364. 接雨水 II

通过具有 16:9 传感器阵列的相机上的 android Camera2 API 捕获 4:3 相机图片

leetcode python 042收集雨水

363. 接雨水

《安富莱嵌入式周报》第288期:微软推出Arm主控PC套件,WiFi信号捕获阵列,下一代雷电4技术,u-boot之父Wolfgang De离开了我们,向大神致敬

CMT2380F32模块开发9-可编程计数阵列 PCA例程