LeetCode 42. 接雨水 Python实现5种算法

42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。LeetCode 42. 接雨水 Python实现5种算法_第1张图片
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

  1. 动态规划(开始想到的)(O(n^2))
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        if n < 3:
            return 0
        dp = [0] * n
        for i in range(2, n):
            if height[i] > height[i - 1]:
                index = i - 1
                j = i - 1
                while index > 0 and height[index] < height[i]:
                    index -= 1
                    if height[index] > height[j]:
                        j = index
                h = min(height[i], height[j])
                dp[i] = dp[j] + (i - j + 1) * h
                for k in range(j, i + 1):
                    dp[i] -= min(h, height[k])
            else:
                dp[i] = dp[i - 1]
        return dp[n - 1]
  1. 暴力法(O(n^2))
    直接按问题描述进行。对于数组中的每个元素,我们找出下雨后水能达到的最高位置,等于两边最大高度的较小值减去当前高度的值。
  2. 动态编程(O(n))
    在暴力方法中,我们仅仅为了找到最大值每次都要向左和向右扫描一次。但是我们可以提前存储这个值。因此,可以通过动态编程解决。
  3. 栈(O(n))
    可以不用像方法 3 那样存储最大高度,而是用栈来跟踪可能储水的最长的条形块。使用栈就可以在一次遍历内完成计算。

在遍历数组时维护一个栈。如果当前的条形块小于或等于栈顶的条形块,我们将条形块的索引入栈,意思是当前的条形块被栈中的前一个条形块界定。如果我们发现一个条形块长于栈顶,我们可以确定栈顶的条形块被当前条形块和栈的前一个条形块界定,因此我们可以弹出栈顶元素并且累加答案到 ans 。

class Solution:
    def trap(self, height: List[int]) -> int:
        ans, current = 0, 0
        stack = []
        while current < len(height):
            while(stack != [] and height[current] > height[stack[-1]]):
                top = stack.pop()
                if stack == []:
                    break
                distance = current - stack[-1] - 1
                bounded_height = min(height[current], height[stack[-1]]) - height[top]
                ans += distance * bounded_height

            stack.append(current)
            current += 1    
        return ans
  1. 双指针(O(n))
    (1)
class Solution:
    def trap(self, height: List[int]) -> int:
        ans = 0
        # 双指针left和right
        left, right = 0, len(height) - 1
        # 记录left左边最大高度left_max和right右边最大高度right_max
        left_max, right_max = 0, 0
        while left < right:
        	# 若此时height[left] < height[right],则left右侧最大高度 >= height[right] > 左侧最大高度left_max(不可能left_max <= height[right],因为left会停留在left_max处)
            if height[left] < height[right]:
                if height[left] < left_max:
                    ans += (left_max - height[left])
                else:
                    left_max = height[left]
                left += 1
            else:
                if height[right] < right_max:
                    ans += (right_max - height[right])
                else:
                    right_max = height[right]
                right -= 1
        
        return ans

(2)更易于理解(转载)

    public int trap(int[] height) {
        if (height.length <= 2)
            return 0;
        int water = 0;
        int left = 0, right = height.length - 1;
        //最开始的时候确定left和right的边界,这里的left和right是
        //柱子的下标,不是柱子的高度
        while (left < right && height[left] <= height[left + 1])
            left++;
        while (left < right && height[right] <= height[right - 1])
            right--;

        while (left < right) {
            int leftValue = height[left];
            int rightValue = height[right];
            //在left和right两根柱子之间计算盛水量
            if (leftValue <= rightValue) {
                //如果左边柱子高度小于等于右边柱子的高度,根据木桶原理,
                // 桶的高度就是左边柱子的高度
                while (left < right && leftValue >= height[++left]) {
                    water += leftValue - height[left];
                }
            } else {
                //如果左边柱子高度大于右边柱子的高度,根据木桶原理,
                // 桶的高度就是右边柱子的高度
                while (left < right && height[--right] <= rightValue) {
                    water += rightValue - height[right];
                }
            }
        }
        return water;
    }

作者:sdwwld
链接:https://leetcode-cn.com/problems/trapping-rain-water/solution/shuang-zhi-zhen-qiu-jie-yu-shui-wen-ti-tu-wen-jie-/
来源:力扣(LeetCode)

你可能感兴趣的:(leetcode,python,leetcode)