当青训营遇上码上掘金
题目
原题如下:
- 现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
相信刷过LeetCode都知道这是很经典的一道"困难"题~,常见的解法便是--单调栈法,本文将重点对单调栈法进行讲解并解题.
栈的简介
栈是一种常用的数据结构,它最大的特点是“后入先出”,即后进入栈中的元素最先出来。为了确保“后入先出”的顺序,栈的插入和删除操作都发生在栈顶。 栈的操作可以用日常生活中的洗碗来理解。假设将洗好的碗堆成一摞。新洗的碗总是放在最上面,每次需要用碗的时候也总是从最上面拿。这一摞碗就相当于一个栈,放碗、取碗操作都发生在一摞碗的顶端,最后放入的碗最先被取走。 在解决很多题目时,我们经常遇到读入的数据暂时用不上的情形,通常数据会先保存到一个数据容器中以后再用。如果数据保存的顺序和使用顺序相反,那么最后保存的数据最先使用,这与栈的“后入先出”特性很契合,可以考虑将数据保存到栈中。很多时候保存在栈中的数据是排序的。根据题目的不同,栈中的数据既可能是递增排序的,也可能是递减排序的。因此,有人将这种用排序的栈解决问题的方法称为单调栈法。下面将开始介绍本题如何使用单调栈法进行解决.
解题
思路:单调递减栈(相同值也更新入栈),柱高作为右墙依次入栈,出现入栈元素(右墙)比栈顶大时,说明在右墙左侧形成了低洼处,低洼处出栈并结算该低洼处能接的豆子. 代码如下:
func trap(height []int) int {
var left, right, leftMax, rightMax, res int
right = len(height) - 1
for left < right {
if height[left] < height[right] {
if height[left] >= leftMax {
leftMax = height[left] // 设置左边最高柱子
} else {
res += leftMax - height[left] // //右边必定有柱子挡水,所以遇到所有值小于等于leftMax的,全部加入水池中
}
left++
} else {
if height[right] > rightMax {
rightMax = height[right] // //设置右边最高柱子
} else {
res += rightMax - height[right] // //左边必定有柱子挡水,所以,遇到所有值小于等于rightMax的,全部加入水池
}
right--
}
}
return res
}