算法题:实现单调栈结构
最近在看左程云的《程序员代码面试指南》,感觉不错,题都分了类,很方便有目的的刷题,书里的代码都是java实现的,刚好最近在学习python,就用python去练习一下。
1. 问题描述
给定一个不含重复值的数组arr, 找到每一个i位置左边和右边离i位置元素最近且比arr[i]小的位置,返回所有位置相应的信息。
举例
数组为arr = [3,4,1,5,6,2,7]
程序结果:
arr[1]左右边最近较小值位置为0和2
arr[0]左右边最近较小值位置为-1和2
arr[4]左右边最近较小值位置为3和5
arr[3]左右边最近较小值位置为2和5
arr[6]左右边最近较小值位置为5和-1
arr[5]左右边最近较小值位置为2和-1
arr[2]左右边最近较小值位置为-1和-1
2.解决方法
单调栈结构:准备一个栈stack,栈中内容是元素在数组中的位置,栈空时或者栈顶元素值比当前元素小时,入栈,否则,弹出,值到满足条件。弹出时,当前元素和弹出后的栈顶元素便分别是弹出的元素的左右最近且最小的元素。
3.代码实现
首先建一个栈类,虽然直接用列表[]也可以
class Stack(object):
def __init__(self):
self.list = []
def is_empty(self):
if self.list:
return False
else:
return True
def pop(self):
if self.is_empty():
print('栈为空!')
return None
else:
result = self.list.pop()
return result
def push(self, item):
self.list.append(item)
def peek(self):
#查看栈顶元素
if self.is_empty():
print('栈为空!')
return None
return self.list[len(self.list) - 1]
def size(self):
#判断大小
return len(self.list)
功能函数
# 功能函数
def getNearLessNoRepeat(arr):
# 本函数通过单调栈实现寻找数组每个元素左右离它最近且比它小的元素位置,元素无重复
res = []
stack = Stack() #里面存储位置信息
i = 0
while i < len(arr):
while not stack.is_empty() and arr[stack.peek()] > arr[i]:
temprary = []
temprary.append(stack.pop()) #现位置信息
if not stack.is_empty(): #左边最近最小数的位置
temprary.append(stack.peek())
else:
temprary.append(-1)
temprary.append(i) #右边最近最小数位置
res.append(temprary)
stack.push(i)
i += 1
while not stack.is_empty():
temprary = []
temprary.append(stack.pop()) #现位置信息
if not stack.is_empty(): #左边最近最小数的位置
temprary.append(stack.peek())
else:
temprary.append(-1)
temprary.append(-1) #右边最近最小数位置,现在因为i已经循环完成了,所以不存在右边最近最小数
res.append(temprary)
return res
主函数
if __name__ == "__main__":
# 数组左右最近较小值,单调栈,元素无重复
arr = [3, 4, 1, 5, 6, 2, 7]
result = getNearLessNoRepeat(arr)
for item in result:
print('arr[{0}]左右边最近较小值位置为{1}和{2}'.format(item[0], item[1], item[2]))
考虑如何有元素重复的情况
进阶功能函数,遇到大小相同的元素时,把它俩放在一起。
def getNearLess(arr):
# 本函数通过单调栈实现寻找数组每个元素左右离它最近且比它小的元素位置,元素可以重复
res = []
stack = Stack() #里面放的是队列
i = 0
while i < len(arr):
while not stack.is_empty() and arr[stack.peek()[0]] > arr[i]:
leftlesslist = stack.pop()
for item in leftlesslist:
temprary = []
temprary.append(item) #现位置信息
if not stack.is_empty(): #左边最近最小数的位置
temprary.append(stack.peek()[len(stack.peek()) - 1]) #最晚加入的最近
# print(stack.peek()[len(stack.peek()) - 1])
else:
temprary.append(-1)
temprary.append(i) #右边最近最小数位置
res.append(temprary)
x = [i,]
if not stack.is_empty() and arr[stack.peek()[0]] == arr[i]:
stack.peek().append(i)
else:
stack.push(x)
i += 1
while not stack.is_empty():
leftlesslist = stack.pop()
for item in leftlesslist:
temprary = []
temprary.append(item) #现位置信息
if not stack.is_empty(): #左边最近最小数的位置
temprary.append(stack.peek()[len(stack.peek()) - 1]) #最晚加入的最近
else:
temprary.append(-1)
temprary.append(-1) #右边最近最小数位置,现在因为i已经循环完成了,所以不存在右边最近最小数
res.append(temprary)
return res