当青训营遇上码上掘金,主题4的攒青豆问题的两种解法
题目描述
「青训营 X 码上掘金」主题创作活动入营版 开启! - 掘金 (juejin.cn)
解法1 按层数豆子
主要思想:如下图所示:按每行来数豆子的个数(如果柱子高度为0,则可以存放一个单位的豆子),我们每数完一层就让柱子的高度减一。
第一层:柱子高度为 [5, 0, 2, 1, 4, 0 ,1, 0, 3],可以攒的豆子数为3
第二层:柱子高度为 [4, 0, 1, 0, 3, 0, 0, 0, 2],可以攒的豆子数为5
第三层:柱子高度为 [3, 0, 0, 0, 2, 0, 0, 0, 1],可以攒的豆子数为6
第四层:柱子高度为 [2, 0, 0, 0, 1, 0, 0, 0, 0],可以攒的豆子数为3
第五层:柱子高度为 [1, 0, 0, 0, 0, 0, 0, 0, 0],可以攒的豆子数为0
因此一共可以攒17个单位的豆子,Go语言代码如下:
func getBeansByLine(height []int) int {
ans := 0
for {
flag := false
tmp := 0
for i, h := range height {
if !flag && h != 0 {
flag = true
height[i]--
continue
}
if flag && h == 0 {
tmp++
continue
}
if h != 0 {
ans += tmp
tmp = 0
height[i]--
}
}
if !flag {
break
}
}
return ans
}
假设柱子数为n,最大高度为m则:时间复杂度为O(n×m),空间复杂度为O(1)
解法2 单调栈
主要思想:用一个单调栈来存储柱子的位置信息,当前柱子高度小于等于栈顶柱子高度时入栈,当前柱子高度大于栈顶柱子高度时出栈,并且计算两根柱子之间可以收集的青豆数,重复直到当前柱子的高度小于等于栈顶柱子高度或者栈空为止。
func getBeansUsingStack(height []int) int {
ans := 0
var 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 { // 长度为0时表示栈为空
break
}
left := stack[len(stack)-1]
distance := i - left - 1 // 柱子之间的距离
minHeight := min(height[left], h) - height[top] // 两根柱子中较短的一根
ans += distance * minHeight
}
stack = append(stack, i)
}
return ans
}
该方法的时间复杂度为O(n),空间复杂度为O(n)