写在前面
最近博主在leetcode上刷题时发现一个新的数据结构:单调栈,可以用来优化时间复杂度,是个利器。楼主在这里做一个单调栈系列总结。
什么是单调栈
单调栈的定义
单调栈,顾名思义,是一个单调的栈。栈内元素一般都是无序的,如何保持栈内元素是有序的呢?接下来,我们进行分析。
单调栈的分类
从数学上,我们知道,单调一般有单调递增和单调递减。那么对于单调栈来说,一般有单调递增栈和单调递减栈。
单调递增栈
单调递增栈,顾名思义,栈内元素保持递增顺序。我们可以实现一下:
单调栈实现基本思想
1、遍历数组元素,同时开辟一个新栈的空间
2、如果当前栈为空,或者当前数组元素的值 > 栈顶元素:
那么将当前数组元素压栈
3、如果当前数组元素的值 < 栈顶元素:
那么将栈顶元素弹出,直至当前数组元素的值 > 栈顶元素 或者 栈为空。
# coding: utf-8
def get_increasing_stack(nums):
"""
给定一个数组,输出为单调递增栈
:param nums:
:return:
"""
stack = []
for num_index in range(len(nums)):
if not stack or nums[num_index] > stack[-1]:
stack.append(nums[num_index])
else:
if nums[num_index] < stack[-1]:
while stack and nums[num_index] < stack[-1]:
stack.pop(-1)
stack.append(nums[num_index])
return stack
if __name__ == '__main__':
nums = [2, 1, 5, 6, 2, 3]
result = get_increasing_stack(nums)
print(result) # 输出为[1, 2, 3]
单调递增栈的作用
1、从上面输出结果来看,如果从左往右遍历数组,可以获取到比当前index
位置的元素的右边第一个大的元素。我们可以想象一下,如果数组从右往左遍历,那么可以获取到比当前index
位置的元素的左边第一个大的元素。
2、一般对于我们来说,利用的是栈的特性,而栈是先进后出的,因此,从栈的角度来看,从左往右遍历:
当栈内元素出栈时,新数组元素是出栈元素向右找第一个比其小的元素
当栈内元素出栈后,新栈顶元素是出栈元素向左找第一个比其小的元素
举个例子说明一下,仍然按上面的例子进行举例:
nums = [2, 1, 5, 6, 2, 3]
单调递减栈
单调递减栈与单调递增栈相反,即栈内元素保持递减顺序。
# coding: utf-8
def get_decreasing_stack(nums):
stack = []
for num_index in range(len(nums)):
if not stack or nums[num_index] < stack[-1]:
stack.append(nums[num_index])
else:
while stack and nums[num_index] > stack[-1]:
stack.pop(-1)
stack.append(nums[num_index])
return stack
if __name__ == '__main__':
nums = [2, 1, 5, 6, 2, 3]
result = get_decreasing_stack(nums)
print(result) # 输出为[6, 3]
单调递减栈的作用
1、从上面输出结果来看,如果从左往右遍历数组,可以获取到比当前index
位置的元素的右边第一小的元素。我们可以想象一下,如果数组从右往左遍历,那么可以获取到比当前index
位置的元素的左边第一小的元素。
2、从栈的角度来看,与递增栈相反,从左往右遍历的话,
当栈内元素出栈时,新数组元素是出栈元素向右找第一个比其大的元素
当栈内元素出栈后,新栈顶元素是出栈元素向左找第一个比其大的元素
举个例子说明一下,仍然按上面的例子进行举例:
nums = [2, 1, 5, 6, 2, 3]:
记忆技巧
有些朋友会说,这绕来绕去我都晕了,到底是个啥情况?
我们只需要记住针对栈的就好了,对比的对象都是出栈元素,假设遍历方向为从左往右。
如果是递增栈的话,栈内元素肯定是递增的,而栈又是先进后出的,故而即将入栈的新元素的位置肯定是在pop出来的元素后面,也就是右边; *栈顶元素的位置肯定是在pop出来的元素前面,也就是左边。*又因为栈内元素递增,pop出来的元素呢肯定是因为新元素比pop出来的元素小才导致被pop的,那么栈顶元素就应该是pop出来元素的左边第一小的元素了,即将新入栈的元素呢就应该是pop出来元素向右找的第一小的元素。
这一篇主要是对单调栈做一个简单剖析,接下来一篇,对单调栈的应用【主要是leetcode上题目】进行剖析。