【困难】42. 接雨水
2024-01-10 02:14:18
题目
42. 接雨水
42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入: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
解题
初步想法:以每一个水平面(连通盛水区)为计算单元。只需要找到这个盛水区的两端就行。依次遍历左板,顺着从左向右找不小于左板的作为右板。
问题:[4,2,3] 这种到最后左高右低的情况不能覆盖
打补丁:最后时候留一个flag(找到左板找不到不小于左板的右板),从右向左再重复遍历
改进:直接找到最高板,左右分别计算。
func trap(height []int) int {
for{
if len(height)>0 && height[0] == 0{
height = height[1:]
} else {
break
}
}
if len(height)<3{
return 0
}
re := 0
imax, max := 0, 0
for ix, v := range height{
if max < v{
max = v
imax = ix
}
}
for i:=0; i<=imax; {
left := i
i++
for left<imax-1 && height[i]<height[left]{
i++
if i > imax{
left++
i = left+1
}
}
if i == left+1{
continue
}
re += count(left, i, height)
}
for i:=len(height)-1; i>=imax; {
right := i
i--
for right>imax+1 && height[i]<height[right]{
i--
if i < imax{
right--
i = right - 1
}
}
if i == right-1{
continue
}
re += count(i, right, height)
}
return re
}
func count(left, right int, height []int) int{
area := min(height[left], height[right]) * (right-left-1)
for i:= left+1;i<right;i++{
area-=height[i]
}
return area
}
问题: 初步没加判断 len(height)>0
…… 小错不断,,,好低级
看了题解自己写一遍动态规划法:
func trap(height []int) int {
left := make([]int, len(height))
right := make([]int, len(height))
left[0] = 0
right[len(height)-1] = 0
for i:=1; i<len(height);i++{
if height[i-1] > left[i-1]{
left[i] = height[i-1]
}else{
left[i] = left[i-1]
}
}
for i:=len(height)-2; i>=0;i--{
if height[i+1] > right[i+1]{
right[i] = height[i+1]
}else{
right[i] = right[i+1]
}
}
re := 0
for i:=0 ; i<len(height);i++{
re += max(min(left[i], right[i])-height[i], 0)
}
return re
}
问题:
- 最后没考虑max的情况,有些例子里当
height[i]
比min(left[i], right[i])
大的时候出现负数…… height[i-1] > left[i-1]
是height[i-1]
与后面的比较
题解
方法一:动态规划
1
func trap(height []int) (ans int) {
n := len(height)
if n == 0 {
return
}
leftMax := make([]int, n)
leftMax[0] = height[0]
for i := 1; i < n; i++ {
leftMax[i] = max(leftMax[i-1], height[i])
}
rightMax := make([]int, n)
rightMax[n-1] = height[n-1]
for i := n - 2; i >= 0; i-- {
rightMax[i] = max(rightMax[i+1], height[i])
}
for i, h := range height {
ans += min(leftMax[i], rightMax[i]) - h
}
return
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
时间:O(n)
空间:O(n)
方法二:单调栈
2
func trap(height []int) (ans int) {
stack := []int{}
for i, h := range height {
for len(stack) > 0 && h > height[stack[len(stack)-1]] {
top := stack[len(stack)-1]
stack = stack[:len(stack)-1]
if len(stack) == 0 {
break
}
left := stack[len(stack)-1]
curWidth := i - left - 1
curHeight := min(height[left], h) - height[top]
ans += curWidth * curHeight
}
stack = append(stack, i)
}
return
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
时间:O(n)
空间:O(n)
方法三:双指针
func trap(height []int) (ans int) {
left, right := 0, len(height)-1
leftMax, rightMax := 0, 0
for left < right {
leftMax = max(leftMax, height[left])
rightMax = max(rightMax, height[right])
if height[left] < height[right] {
ans += leftMax - height[left]
left++
} else {
ans += rightMax - height[right]
right--
}
}
return
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
时间:O(n)
空间:O(1)
长进
- 问题: 初步没加判断
len(height)>0
…… 小错不断,,,好低级 - 出现问题的用例
- [4,2,3]
- [0]
- [0,1,2,0,3,0,1,2,0,0,4,2,1,2,5,0,1,2,0,2] 这个是使用flag方法,和用最大值基本一致,但是写的有bug,没再改,直接改为最大值方案。
- 后续自己复盘重写一下单调栈和双指针
文章来源:https://blog.csdn.net/Miller_6/article/details/135467564
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!