ethan

ethan

新知,热爱生活,码农,读书
twitter
email
github

LCR 42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

 image.png
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105

解法 1:单调栈
解题思路:
对于低的柱子入栈,当出现比栈顶高的柱子,则认为可以进行一波计算。计算雨水的时候需要注意的是雨水区域的右边 r 指的自然是当前索引 i 底部是栈顶 ,因为遇到了更高的右边,所以它即将出栈,使用cur 来记录它,并让它出栈左边l 就是新的栈顶雨水的区域全部确定了,水坑的高度就是左右两边更低的一边减去底部,宽度是在左右中间使用乘法即可计算面积。

func trap(height []int) int {
	stack := make([]int, 0)
	ret := 0
	for i := 0; i < len(height); i++ {
		for len(stack) != 0 && height[stack[len(stack)-1]] < height[i] {
			cur := stack[len(stack)-1]
			stack = stack[:len(stack)-1]
			if len(stack) == 0 {
				break
			}
			h := height[i]
			if height[stack[len(stack)-1]] < h {
				h = height[stack[len(stack)-1]]
			}
			w := i - stack[len(stack)-1] - 1
			ret += w * (h - height[cur])
		}
		stack = append(stack, i)
	}
	return ret
}

解法 2: 当前柱子能否蓄水,取决于左右的最大值和当前柱子的差值

func max_num(arr []int) int {
    max := 0
    for i:= 0; i< len(arr);i++ {
        x := arr[i]
        if x > max {
            max = x
        }
    }
    return max
}
func trap(height []int) int {
    left_max_arr := make([]int, 0)
    right_max_arr := make([]int, 0)
    ret := 0
	for i:=0;i<len(height);i++ {
        left_max_arr  = append(left_max_arr, max_num(height[:i]))
        right_max_arr = append(right_max_arr, max_num(height[i:]))
    }
    for i:=0;i<len(height);i++ {
        if left_max_arr[i] < right_max_arr[i] {
            if left_max_arr[i]> height[i] {
                ret += left_max_arr[i] - height[i]
            }
        }else{
            if right_max_arr[i] > height[i] {
                ret += right_max_arr[i] - height[i]
            }
        }
    }
    return ret
}

解法三:双指针解法
从上面的思路,很容易引出双指针解法,将算法的空间复杂度从 o (n) 降到 o (1)

func trap(height []int) int {
	left := 0
    right := len(height)-1
    left_max := 0
    right_max := 0
    ret := 0
    for left < right {
        water_level := left_max
        if left_max > right_max {
            water_level = right_max
        }
        if height[left] <= water_level {
            ret += water_level-height[left]
            left += 1
            continue
        }
        if height[right] <= water_level {
            ret += water_level-height[right]
            right -= 1
            continue
        }
        if left_max < height[left] {
            left_max = height[left]
        }
        if right_max < height[right] {
            right_max = height[right]
        }
    }
    return ret
}
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。