Trapping Rain Water
题目描述
接雨水:
给定用n个非负整数表示的、高度为1的柱子图,计算按此排列的柱子,下雨后可以接多少水。
示例:
输入:[0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解法
解法一:按行寻找
时间复杂度:
O(M * N)
,M是最大高度空间复杂度:
O(1)
func trap(height []int) int {
max := 0
for _, v := range height {
if max < v {
max = v
}
}
total := 0
// 计算每一行的雨水 再累加
for h := 1; h <= max; h++ {
// begin 用来过滤最开始不满足要求的柱子
begin, tmp := false, 0
for j := range height {
// 如果高度足够 累计雨水数
if height[j] >= h {
total += tmp
begin = true
tmp = 0
}
if begin && height[j] < h {
tmp++
}
}
}
return total
}
解法二:按列寻找
时间复杂度:
O(n^2)
空间复杂度:
O(1)
func trap(height []int) int {
var total int
for i := 1; i < len(height)-1; i++ {
var max_left, max_right int
for j := i; j >= 0; j-- {
if height[j] > max_left {
max_left = height[j]
}
}
for j := i; j < len(height); j++ {
if height[j] > max_right {
max_right = height[j]
}
}
if max_left < max_right {
total += max_left - height[i]
} else {
total += max_right - height[i]
}
}
return total
}
解法三:预处理左右边界
时间复杂度:
O(n)
空间复杂度:
O(1)
func trap(height []int) int {
n := len(height)
// 位置i的左右边界
left, right := make([]int, n), make([]int, n)
for i := range height {
if i == 0 || height[i] > left[i-1] {
left[i] = height[i]
} else {
left[i] = left[i-1]
}
if i == 0 || height[n-1-i] > right[n-i] {
right[n-1-i] = height[n-1-i]
} else {
right[n-1-i] = right[n-i]
}
}
total := 0
for i := 1; i < n-1; i++ {
if left[i] > right[i] {
total += right[i] - height[i]
} else {
total += left[i] - height[i]
}
}
return total
}
解法四:单调栈
时间复杂度:
O(n)
空间复杂度:
O(n)
func trap(height []int) int {
var total int
stack := []int{}
for i := 0; i < len(height); i++ {
length := len(stack)
// 位置i作为右边界 计算容器雨水值
for length > 0 && height[i] > height[stack[length-1]] {
top := stack[length-1]
stack = stack[:length-1]
length--
if length <= 0 {
break
}
newTop := stack[length-1]
width := i - newTop - 1
if height[newTop] > height[i] {
total += (height[i] - height[top]) * width
} else {
total += (height[newTop] - height[top]) * width
}
}
stack = append(stack, i)
}
return total
}
解法五:双指针法
时间复杂度:
O(n)
空间复杂度:
O(1)
func trap(height []int) int {
// 使右边界一定大于左边界
var maxLeft, maxRight, total int
left, right := 0, len(height)-1
for left < right {
if height[left] < height[right] {
if maxLeft < height[left] {
maxLeft = height[left]
} else {
total += maxLeft - height[left]
}
left++
} else {
if maxRight < height[right] {
maxRight = height[right]
} else {
total += maxRight - height[right]
}
right--
}
}
return total
}
Last updated
Was this helpful?