[LeetCode] 42. Trapping Rain Water 收集雨水

与世无争的帅哥 提交于 2020-05-08 04:13:32

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.


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!

Example:

Input: [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6

解法1:双指针Two Pointers,left和right分别指向数组的头尾,从两边向中间扫描,在当前两指针的范围内,先比较两头找出较小值,如果较小值是left指向的值,则从左向右扫描,如果较小值是right指向的值,则从右向左扫描,若遇到的值比当较小值小,则将差值存入结果,如遇到的值大,则重新确定新的窗口范围,迭代直至left和right指针重合。

对于任何一个坐标,检查其左右的最大坐标,然后相减就是容积。所以, 
1. 从左往右扫描一遍,对于每一个坐标,求取左边最大值。
2. 从右往左扫描一遍,对于每一个坐标,求最大右值。
3. 再扫描一遍,求取容积并加和。
2和3可以合并成一个循环,公式:H[i] = min(Max(Array[j] ),  Max(Array[k])) – Array[i]  where  j < i and k > i

解法2:栈stack

Follow up:

不求所有容积,而是求容积中的最大值。这样就类似于Container With Most Water,但是有不同的地方,这题里面每一个坐标本身是占体积的。所以从两边往中间扫的时候,根本不知道中间坐标共占用了多少体积。

Java:

public class Solution {
    public int trapRainWater(int[] heights) {
        if (heights.length == 0) {
            return 0;
        }
        
        int[] maxHeights = new int[heights.length + 1];
        maxHeights[0] = 0;
        for (int i = 0; i < heights.length; i++) {
            maxHeights[i + 1] = Math.max(maxHeights[i], heights[i]);
        }
        
        int max = 0, area = 0;
        for (int i = heights.length - 1; i >= 0; i--) {
            area += Math.min(max, maxHeights[i]) > heights[i]
                    ? Math.min(max, maxHeights[i]) - heights[i]
                    : 0;
            max = Math.max(max, heights[i]);
        }
        
        return area;
    }
}

Java: 参考

public class Solution {
    public int trap(int[] height) {
        Stack<Integer> st = new Stack<Integer>();
        if(height.length == 0)
            return 0;
        int i = 0;
        int j = height.length - 1;
        int ans = 0;//返回的答案
        int secHight = 0;//第二个高度(最高的那个不动)
        while(i < j){
            if(height[i] < height[j]){
                secHight = Math.max(secHight,height[i]);
                //因为长度为1,高度也就是面积值,如果height[i]==secHight,则新增面积为0
                ans += secHight - height[i];
                i++;
            }else{
                secHight = Math.max(secHight,height[j]);
                //因为长度为1,高度也就是面积值,如果height[i]==secHight,则新增面积为0
                ans += secHight - height[j];
                j--;
            }
        }
        return ans;
    }
}  

Python:

class Solution:
    # @param A, a list of integers
    # @return an integer
    def trap(self, A):
        result = 0
        top = 0
        for i in xrange(len(A)):
            if A[top] < A[i]:
                top = i

        second_top = 0
        for i in xrange(top):
            if A[second_top] < A[i]:
                second_top = i
            result += A[second_top] - A[i]

        second_top = len(A) - 1
        for i in reversed(xrange(top, len(A))):
            if A[second_top] < A[i]:
                second_top = i
            result += A[second_top] - A[i]

        return result

Python:

# Time:  O(n)
# Space: O(n)
class Solution2:
    # @param A, a list of integers
    # @return an integer
    def trap(self, A):
        result = 0
        stack = []

        for i in xrange(len(A)):
            mid_height = 0
            while stack:
                [pos, height] = stack.pop()
                result += (min(height, A[i]) - mid_height) * (i - pos - 1)
                mid_height = height

                if A[i] < height:
                    stack.append([pos, height])
                    break
            stack.append([i, A[i]])

        return result

Python: wo

class Solution(object):
    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        if not height:
            return 0
        res = 0
        left, right = 0, len(height) - 1
        left_max, right_max = 0, 0
        while left < right:
            if height[left] < height[right]:
                left_max = max(left_max, height[left])
                left += 1
                res += max(0, left_max - height[left])
            else:
                right_max = max(right_max, height[right])
                right -= 1
                res += max(0, right_max - height[right])
                
        return res    

C++:

// Time:  O(n)
// Space: O(1)
class Solution {
public:
    int trap(vector<int>& height) {
        if (height.empty()) {
            return 0;
        }

        int i = 0, j = height.size() - 1;
        int left_height = height[0];
        int right_height = height[height.size() - 1];
        int trap = 0;

        while (i < j) {
            if (left_height < right_height) {
                ++i;
                // Fill in the gap.
                trap += max(0, left_height - height[i]);
                // Update current max height from left.
                left_height = max(left_height, height[i]);
            }
            else {
                --j;
                // Fill in the gap.
                trap += max(0, right_height - height[j]);
                // Update current max height from right.
                right_height = max(right_height, height[j]);
            }
        }

        return trap;
    }
};

C++:

int trap(vector<int>& height) {
    int l = 0, r = height.size()-1, level = 0, water = 0;
    while (l < r) {
        int lower = height[height[l] < height[r] ? l++ : r--];
        level = max(level, lower);
        water += level - lower;
    }
    return water;
}

C++:

#include <bits/stdc++.h>
 
using namespace std;
 
// two pointers
class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
		// Exceptional Case: 
		if(n <= 2){
			return 0;
		}
		int ans = 0;
		int left = 0, right = n - 1;
		while(left < right){
			int min_height = min(height[left], height[right]);
			if(height[left] == min_height){
				while(++left < right && height[left] <= min_height){
					ans += (min_height - height[left]);
				}
			}
			else if(height[right] == min_height){
				while(left < --right && height[right] <= min_height){
					ans += (min_height - height[right]);
				}
			}
		}
		return ans;
    }
};

  

    

 

类似题目:

[LeetCode] 11. Container With Most Water 装最多水的容器

[LeetCode] 407. Trapping Rain Water II 收集雨水 II

 

All LeetCode Questions List 题目汇总

 

 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!