单调栈:每日温度
- 请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替
- 单调栈基本只处理NGE问题(Next GreaterElement)。对序列中每个元素,找到下一个比它大的元素。(“下一个”可以换成“上一个”,“大”也可以换成“小”)
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
// NGE问题,单调栈,按温度递减的顺序,排列日期
Deque<Integer> descStack = new LinkedList<>();
int[] result = new int[temperatures.length];
for (int i = 0; i < temperatures.length; i++) {
// 保证栈是递减的
while (descStack.size() > 0 && temperatures[descStack.peekLast()] < temperatures[i] ) {
int topDay = descStack.pollLast();
result[topDay] = i - topDay;
}
descStack.offerLast(i);
}
return result;
}
}
单调队列:滑动窗口的最大值
-
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值(典型用法)
"""
用一个queue(滑动窗口,先入先出)和一个deque实现
queue负责push和pop,deque用来存放最大值
1. 如果新的value大于deque尾端的值,那么deque一直进行pop_back操作,直到尾端的值大于等于value 或者为空,再将value压入deque的尾部
2. 每次取max_value,返回deque首部的值
3. 当que进行pop操作时,如果que首部的值等于deque首部的值,那么deque同样需要进行pop_front操作
"""
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
// 单调队列
Deque<Integer> queue = new LinkedList<>();
List<Integer> result = new LinkedList<>();
// 窗口不满,处理前k个值
for (int i = 0; i < k; i++) {
while (!queue.isEmpty() && queue.peekLast() < nums[i]) {
queue.pollLast();
}
queue.offerLast(nums[i]);
}
result.add(queue.peekFirst());
// 窗口已满,处理后续值
for (int i = k; i < nums.length; i++) {
int outVal = nums[i - k];
int inVal = nums[i];
// 最大值出窗口,要在队列中同步删除
if (outVal == queue.peekFirst()) {
queue.pollFirst();
}
// 新值进窗口
while (!queue.isEmpty() && queue.peekLast() < nums[i]) {
queue.pollLast();
}
queue.offerLast(nums[i]);
result.add(queue.peekFirst());
}
return result.stream().mapToInt(Integer::intValue).toArray();
}
}
单调队列:队列的最大值
- 栈的最值比较简单(每次入栈两个元素,一个当前值,一个当前最值)
class MaxQueue {
// 单调队列,用于统计当前队列的最值
Deque<Integer> deque = new LinkedList<>();
// 存放当前队列的所有元素
List<Integer> list = new LinkedList<>();
public MaxQueue() {
}
public int max_value() {
if (deque.isEmpty()) {
return -1;
} else {
// 单调队列的首部是最值
return deque.peekFirst();
}
}
public void push_back(int value) {
list.add(value);
// 维护单调队列使其保持递减
while (!deque.isEmpty() && deque.peekLast() < value) {
deque.pollLast();
}
deque.offerLast(value);
}
public int pop_front() {
if (deque.isEmpty()) {
return -1;
}
int result = list.get(0);
list.remove(0);
// 如果出队列的值是当前最大值,同步移除
if (deque.peekFirst() == result) {
deque.pollFirst();
}
return result;
}
}