单调栈的定义与应用

定义:

单调栈是一种特殊的栈结构,通常用于解决一类特定的问题,如找到数组中元素的下一个更大(或更小)元素。它的核心特性是维护栈内元素的单调性,即栈内元素按照从栈底到栈顶的顺序,要么严格递增,要么严格递减。
也即:
单调递增栈:从栈底到栈顶,依次递增的顺序
单调递减栈:从栈底到栈顶,依次递减的顺序

单调递增栈:
遍历列表,对于列表遍历的每个元素,如果元素比栈顶小,栈出栈,拿该元素继续比较栈顶元素,直到该元素比栈顶元素大时入栈,该元素相对小,否则一直出栈,直到该元素可能排在栈底,该元素在当次的最小元素
单调递减栈:
遍历列表,对于列表遍历的每个元素,如果元素比栈顶大,栈出栈,拿该元素继续比较栈顶元素,直到该元素比栈顶元素小时入栈,该元素相对大,否则一直出栈,直到该元素可能排在栈底,该元素在当次的最大元素

应用

769-每日温度

给定一个温度列表,表中数据为每日的温度值,找出每天温度对应在几天后会出现比其温度更高的值,返回每天温度对应几天后温度更高。

这其实就是一个单调递减栈的应用。

先看看 golang 代码实现:

package main

func main() {
	temperatures := []int{73, 74, 75, 71, 69, 72, 76, 73}
	dailyTemperatures(temperatures)
}

func dailyTemperatures(nums []int) []int {
	ans := make([]int, len(nums))
	stack := []int{}

	for i, v := range nums {
		for len(stack) > 0 && v > nums[stack[len(stack)-1]] {
			var top int = stack[len(stack)-1]
			stack = stack[:len(stack)-1]
			ans[top] = i - top
		}

		stack = append(stack, i)
	}

	return ans
}

对于算法流程,

  • 先初始化返回值,先依次遍历输入数组,
  • 对于遍历的每个值,都与栈顶元素(索引)对应的温度比较,只要当前遍历的温度大于栈顶元素对应的温度值,认为找到第一个比栈顶索引对应温度更高的值,出栈索引值,当前遍历温度的索引-出栈元素(索引),就是该出栈元素对应温度的间隔时间天数,填回返回值中,不断循环遍历栈,直到当前遍历元素值不大于栈顶元素对应温度值,
  • 每次遍历最后,当前遍历元素的索引值入栈,重复遍历直到结束。

以具体例子说明算法流程:

1.遍历第一个元素73,由于栈空,不遍历栈做比较,直接入栈73对应的索引值0
2.遍历到第二个元素74,由于栈非空,可遍历栈进行比较74与栈顶元素0对应的温度73,74>73,可知,74是73温度对应的第一个比它大的值,记录下间隔时间1-0,对应的是ans[0] = 1-0,出栈0元素,此时栈空,退出二层循环,入栈新元素1,此时栈为[1]
3.遍历第三个元素75,栈非空,75与栈顶元素1对应的值74比较,75>74,即1位置对应的温度74找到了第一个比其高的元素75,记录ans[1] = 2-1,出栈1,此时栈空,该轮遍历加入75对应的索引2,栈为[2]
4.遍历第四个元素71,栈非空,但71小于栈顶元素对应值75,直接入栈71元素对应索引,此时栈[2, 3]
5.遍历第五个元素69,类似71,69<71,入栈,栈[2,3,4](实际对应的温度是[75, 71, 69])
6.遍历第六个元素72,显然72>栈顶元素4对应的69,记录ans[4] = 5-4,出栈4,栈[2,3],继续遍历栈,72>栈顶元素3对应的71,记录ans[3] = 5-3,出栈3,栈[2],再遍历72<2对应的75,退出二层循环,加入当次遍历的索引5,栈[2, 5](栈对应温度值[75, 72])
7.遍历第七个元素76,遍历栈,显然76>5对应的72,记录ans[5] = 6-5,出栈5,栈[2],继续遍历栈,76>2对应的75,记录ans[2] = 6-2,出栈2,栈空,退出二层循环,入栈元素6
8.遍历第八个元素73,栈非空,但73<栈顶元素6对应的76,入栈7,栈[6, 7]
9.结束遍历,此时ans = [1, 1, 4, 2, 1, 1, 0, 0]即为答案

posted on 2024-02-24 10:09  进击的davis  阅读(7)  评论(0编辑  收藏  举报

导航