python数据结构——单调栈和单调队列

单调栈

数据结构栈遵循先进后出的原则,在python中,利用list就可以实现栈的功能

stack = []
stack.append(1)
stack.append(2)
print(stack.pop()) #2

单调栈遵循单调增或者单调减的原则,用于处理某些特别的任务,也就是常说的next greater element的问题。

class MStack:
	def __init__(self):
		self.stack = []
	
	def push(self, value):
		while self.stack and stack[-1] <= value:
			self.pop()
		self.stack.append(value)
	
	def pop(self):
		return self.stack.pop(-1)

例如,给定一个数组,求出每个数后面更大的数,这就是一个 基础next greater element的问题。比如数组是[3, 1, 2, 8, 3, 5],返回的结果为[8, 8, 8, -1, 5, -1],3的下一个最大的数为8,后面同理,8后面最大的数不存在,所以是-1。
这类题目的解法都基于如上的单调栈框架:

def nextGreatNumber(nums):
	n = len(nums)
	ans = [-1 for _ in range(n)]
	stack = []
	for i in range(n-1, -1, -1):
		while stack and stack[-1] <= nums[i]:
			stack.pop()
		if stack:
			ans[i] = stack[-1]
		stack.append(nums[i])
	return ans

这里有几个问题:

  • 为什么要从相反的方向遍历?
    要找到下一个更大的元素,可以尝试理解为从下一个更大的元素往前看,能看到nums[i]时候的元素就是下一个更大的数,因为中间的数,如果中间有一个比nums[i]更大的数,那站在后侧是看不到nums[i]的,因为被该数挡住了。
    此外,留在栈中的元素都是比nums[i]大的元素,这样,栈中就是维持单调递减的一个状态,栈尾的元素永远是栈中最小的元素,也是更靠近nums[i]的元素,while循环的作用就是把比nums[i]小的元素都拿走,因为他们在前面的数看来,都会被 nums[i]挡住。
  • 算法的时间复杂度是o(n^2)?
    其实不然,虽然看似,有两层循环,但是实际上每个元素只会被压入栈一次, 而出栈也就仅有少数几个数(一般为两个大数,中间的小数),所以复杂度依旧是o(n)。

单调队列

队列满足先进先出原则,单调队列同理,也是专门设计出来解决某种问题,单调队列的结构如下:

class MQueue:
	def __init__(self):
		self.queue = []
	
	def push(self, value):
		while self.queue and self.queue[-1] < value:
			self.queue.pop(-1)
		self.queue.append(value)
	
	def pop(self):
		if self.queue:
			return self.queue.pop(0)

在python中,单调队列在构建时单调栈类似,只是在pop时候是选择弹出列表头,其他语言多采用双向队列进行构建。
单调队列在解决某些问题时,能提升效率(如滑动窗口最大值)。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值