leetcode刷题笔记四十二 接雨水
leetcode刷题笔记四十二 接雨水
源地址:42. 接雨水
问题描述:
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [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
代码补充:
//方法一: 直接统计每个柱子的储水情况
//对于单个柱子的储水值,受其左侧柱子最大高度及右侧柱子最大高度
//即 储水值 = (左侧最大柱子高度与右侧最大柱子高度的较小值)- 当前柱子高度
//实际处理过程中,需要将当前柱子加入到左右侧柱子最大高度的计算中,防止出现负数值,这种情况下整个数组的最大高度的储水值会为0
//时间复杂度O(n^2) 空间复杂度O(1)
import scala.math
object Solution {
def trap(height: Array[Int]): Int = {
var res = 0
//就整个数组中的每个柱子的储水值进行计算
for (i <- 0 until height.length){
//将当前柱子高度包含在内,计算左侧柱子最大高度
var max_left = 0
for(j <- 0 to i){
if (height(j) > max_left) max_left = height(j)
}
//将当前柱子高度包含在内,计算右侧柱子最大高度
var max_right = 0
for(j <- i until height.length){
if (height(j) > max_right) max_right = height(j)
}
//将每个柱子上的储水值进行统计
res += (math.min(max_left, max_right) - height(i))
}
return res
}
}
//方法二: 动态规划
//基于上述方法,可见对于每个柱子使用的数据主要为其max_left及max_right
//构建两个数组 记录每个柱子的max_left和max_rigth
//时间复杂度O(n) 空间复杂度O(n)
import scala.math
object Solution {
def trap(height: Array[Int]): Int = {
if (height.length == 0) return 0
var res = 0
val max_left_matrix = new Array[Int](height.length)
val max_right_matrix = new Array[Int](height.length)
//初始化数组
max_left_matrix(0) = height(0)
max_right_matrix(height.length-1) = height(height.length-1)
//更新左侧柱子最大高度数组
for(i <- 1 to height.length-1) max_left_matrix(i) = math.max(max_left_matrix(i-1),height(i))
//更新右侧柱子最大高度数组
//注意Scala倒叙计数的方法, 使用reverse方法
for(i <- (0 to height.length-2).reverse) max_right_matrix(i) = math.max(max_right_matrix(i+1), height(i))
//根据公式,计算每个柱子的储水值并累加
for(i <- 0 to height.length-1) res += math.min(max_left_matrix(i), max_right_matrix(i)) - height(i)
return res
}
}
//方法三:双指针法
//维持一个稳定的max_left 和 max_right,将随着left,right指针收敛进行更新
//时间复杂度O(n) 空间复杂度O(1)
import scala.math
object Solution {
def trap(height: Array[Int]): Int = {
if (height.length == 0) return 0
var res = 0
var max_left = 0
var max_right = 0
var left = 0
var right = height.length-1
while(left <= right){
//max_left <= max_right时,使用max_left进行判断
//推动left向前,因为max_left较max_right小,若left
//不向前,始终会选择max_eft作为评价
if(max_left <= max_right){
max_left = math.max(max_left, height(left))
res += max_left - height(left)
left += 1
}
//同left直至双指针重合
else{
max_right = math.max(max_right, height(right))
res += max_right - height(right)
right -= 1
}
}
return res
}
}
//方法四:单调栈
//储水的槽构成需要三根柱子,即单调栈中比栈顶元素大的左侧柱
//栈顶元素 与 目前访问的数组的柱高 这才可能构成凹槽储水
//以图例演示储水情况
// 4
// 4 3
// 4 3 2
// 4 3 2 0 ===》 因为缺乏有效的右侧,无法计算储水
// 4 3 2 0 <--- 1 此处构成凹槽 将0弹出 计算高度为0的层的储水值 res += (4-2-1)*(1-0)
// 4 3 2 1 <---3 此处又构成凹槽 将1弹出 计算高度为1的层的储水值 res += (5-2-1)*(2-1)
//以此类推
import scala.math
import scala.collection.mutable.Stack
object Solution {
def trap(height: Array[Int]): Int = {
if (height.length == 0) return 0
var res = 0
val stack = new Stack[Int]()
for(i <- 0 to height.length-1){
var last = 0
while(stack.isEmpty == false && height(stack.top) <= height(i)){
val temp = stack.top
stack.pop
res += (i - temp - 1)*(height(temp) - last)
last = height(temp)
}
if (stack.isEmpty == false) res += (i - stack.top - 1)*(height(i) - last)
stack.push(i)
}
return res
}
}