42. 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.

The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!

思路1:

这个题可以逐层扫描,每一次减掉最低的非0高度。但是这个的问题是如果说height里大于0且distinct的数有m个,就loop m次。 很容易就超时了。

具体code如下:

public int Trap(int[] height) {
        int res = 0;
        int count =0;
        foreach(var h in height) count+= h;

        while(count>1)
        {
            int j =0;
            
            while(height[j] == 0)
            {
                j++;
            }
            int trap = j;
            int a = 0;
            int minTrap = height[j];
            for(int i =j+1;i< height.Count();i++)
            {
                if(height[i] !=0)
                {
                    minTrap = Math.Min(minTrap,height[i]);
                    a += Math.Max(0,i-trap-1);
                    trap = i;
                }
            }
            res += a*minTrap;
            for(int i =0;i< height.Count();i++)
            {
                if(height[i]>0)
                {
                    count-=minTrap;
                    height[i] -=minTrap;
                }
            }
            
        }
        return res;
    }

解法2: 

每一个slot的位置,它能储水的量为其左边最高高度与右边最高高度的最小值与其本身高度的差,举个例子,如果在i=5的位置,i左边最高位置为9, 右边最高位置为7, 那这个地方能储水的量就是Math.Min(9,7) - 5 = 2. 所以我们设置一个dp数组,dp[i]记录i位置左侧最高高度,左遍历一遍;再设置一个dp数组,dp[i]记录i位置右侧最高高度,右遍历一遍;然后再loop一遍即可算出大小。

code如下:

public int Trap(int[] height) {
        int res = 0;
        int size = height.Count();
        var leftMax = new int[size];
        var rightMax  = new int[size];
        
        for(int i =1;i< size;i++)
        {
            leftMax[i] = Math.Max(height[i-1],leftMax[i-1]);
        }
        for(int i =size-2;i>=0;i--)
        {
            rightMax[i] = Math.Max(height[i+1], rightMax[i+1]);
        }
        
        for(int i =1;i< size-1;i++)
        {
            int min = Math.Min(leftMax[i],rightMax[i]);
            if(height[i]<min)
            {
                res += min-height[i];
            }
        }
        
        return res;
    }

解法3:

我们也可以用stack,这个就是比较慢,stack压入的是比stack.Peek()小的值,这样每一个0都会被压进去。计算的时候当height[i]大于stack.Peek时候,就需要先pop一个值出来,这个是底,然后再用stack.Peek()与height[i]的最小值, 减掉底,然后乘以index的差。这个地方因为

public int Trap(int[] height) {
        int max =0;
        int res = 0;
        int size = height.Count();
        if(size <= 2) return res;
        int i =0;
        var stack = new Stack<int>();//store the largerst heigth index
        while(i< size)
        {
            if(stack.Count()==0 || height[i] <= height[stack.Peek()]) stack.Push(i++);
            else
            {
                int bot = stack.Pop();
                res += (stack.Count()==0)?0:((Math.Min(height[stack.Peek()], height[i]) - height[bot])*(i - stack.Peek()-1));; 
            }
        }
        return res;
    }
原文地址:https://www.cnblogs.com/renyualbert/p/6002606.html