单调栈
- 单调栈
- 概念
- 每日温度
单调栈
概念
单调栈(Monotonic Stack)是一个特殊的数据结构,它是一种栈,但具有单调性的特性。单调栈有两种类型:单调递增栈和单调递减栈。
在单调递增栈中,栈内的元素保持递增顺序,即后入栈的元素总是大于或等于先入栈的元素。同样,在单调递减栈中,栈内的元素保持递减顺序,即后入栈的元素总是小于或等于先入栈的元素。
以下是一个单调栈的基本实现(以单调递减栈为例):
def monotone_stack(nums):
stack = []
result = [-1] * len(nums)
for i in range(len(nums)):
while stack and nums[i] < nums[stack[-1]]:
# 出栈,并记录右边第一个比其小的元素的下标
result[stack.pop()] = i
stack.append(i)
# 处理剩余栈内元素
while stack:
result[stack.pop()] = len(nums)
return result
这个函数会返回一个列表,表示每个元素的右边第一个比其小的元素的下标。如果没有这样的元素,则返回数组长度(表示该元素右边没有其他元素)。注意,这个实现是针对单调递减栈的,如果需要单调递增栈,只需将比较符号从 <
改为 >
即可。
举个例子,对于输入数组 [5, 3, 1, 4, 2]
,单调递减栈的输出为 [4, 2, 1, 5, -1]
。这表示:
- 数字 5 右边第一个比它小的数字是 4(下标为 3)
- 数字 3 右边第一个比它小的数字是 2(下标为 4)
- 数字 1 右边没有比它小的数字(下标为 -1)
- 数字 4 右边第一个比它小的数字是 2(下标为 4),但实际上这个输出是不准确的,因为数字 2 在数字 4 的左边。这里我们可以看到,这个实现其实是在找右边第一个比其小的元素,而不是左边。
- 数字 2 右边没有比它小的数字(下标为 -1)
注意,上述例子的输出描述有误。实际上,对于输入数组 [5, 3, 1, 4, 2]
,正确的输出应该是每个元素的右边第一个比其大的元素的下标。为了得到左边第一个比其大的元素的下标,我们需要稍微修改一下算法。
这是一个更准确的描述和示例,展示如何使用单调栈找到每个元素左边第一个比其大的元素的位置:
def monotone_stack(nums):
stack = []
result = [-1] * len(nums) # 初始化结果列表,所有位置先设为-1
for i in range(len(nums)):
while stack and nums[i] > nums[stack[-1]]:
# 当前元素比栈顶元素大,所以栈顶元素的左边第一个比它大的元素就是当前元素
result[stack.pop()] = i
stack.append(i) # 将当前元素下标入栈
return result
# 示例
nums = [5, 3, 1, 4, 2]
print(monotone_stack(nums)) # 输出: [-1, 0, -1, 0, 3]
在这个修正后的示例中:
- 数字 5 左边没有比它大的数字(下标为 -1)
- 数字 3 左边第一个比它大的数字是 5(下标为 0)
- 数字 1 左边没有比它大的数字(下标为 -1)
- 数字 4 左边第一个比它大的数字是 5(下标为 0),注意这里不是 3,因为我们要找的是比 4 大的数字
- 数字 2 左边第一个比它大的数字是 4(下标为 3)
这样,我们就得到了每个元素左边第一个比其大的元素的位置。
每日温度
https://leetcode.cn/problems/daily-temperatures/description/?envType=study-plan-v2&envId=top-100-liked
public static int[] dailyTemperatures(int[] temperatures){ // 栈一直单调递减
int n = temperatures.length;
int[] res = new int[n];
LinkedList<Integer> stack = new LinkedList<>();
for (int i = temperatures.length - 1; i >= 0; i--) {
int t = temperatures[i];
while (!stack.isEmpty() && t>=temperatures[stack.peek()]){// 有比之前大的数字就弹出去
stack.pop();
}
if(!stack.isEmpty()){
res[i] = stack.peek()-i;
}
stack.push(i);
}
return res;
}