参考《程序员面试指南:IT名企算法于数据结构题目最优解(第2版)》
单调栈
单调栈是一种从栈顶到栈底单调递增或单调递减的栈。
它常用于解决离某位置最近的最大或者最小值这种问题。
不含重复值的数组
问题描述
给定一个不含重复值的数组
arr
,找到每一个i
位置左边和右边离i
位置最近且值比arr[i]
小的位置。返回所有位置相应的信息,不存在则为-1
。
示例:
输入:arr = [3, 4, 1, 5, 6, 2, 7]
输出:[(-1, 2), (0, 2), (-1, -1), (2, 5), (3, 5), (2, -1), (5, -1)]
暴力解法
时间复杂度为 O ( N 2 ) \mathcal{O}(N^2) O(N2),每个位置分别向左和向右遍历即可。
单调栈解法
时间复杂度为 O ( N ) \mathcal{O}(N) O(N)。
大致思路是维护一个单调栈stack
和结果数组res
,因为是找最小值,所以为从栈顶到栈底单调递减的栈,栈中保存的是arr
中的位置。
- 如果当前遍历到的值比栈顶元素对应
arr
中的值大,那么直接入栈; - 若比栈顶元素对应
arr
中的值小,那么弹出栈顶元素对应的结果就可确定了,当前遍历的值为其右边最近且比它小的值,新的栈顶元素为其左边最近且比它小的值。 - 如果
arr
中元素已经遍历完则判断stack
是否为空,若为空,则已经得到最终的结果了,若stack
不为空,则需要一次弹出stack
的栈顶元素,此时剩下的这些元素不存在位于其右边且比之小的值,所以全部为-1,而只要还有新的栈顶元素即为其左边且比之小的值,如果弹出当前元素后为空,则其res
中的值为(-1, -1)
。
arr = [3, 4, 1, 5, 6, 2, 7]
n = len(arr)
stack, res = [], [None] * n
for i in range(n):
while stack and arr[i] < arr[stack[-1]]:
cur = stack.pop()
left_less = -1 if not stack else stack[-1]
res[cur] = (left_less, i