一.原题如下:
二.滑动窗口是什么?
处理数组问题或字符串问题的算法技巧;
核心思想是维护一个窗口,窗口左右边界根据条件动态调整,窗口大小可以固定也可以可变
三.滑动窗口在Java中的应用场景有哪些?
- SpringCloud Gateway 或 SpringCloud Sentinel:限流与熔断
- SpirngCloud Micrometer 或 Prometheus:实时数据统计,比如QPS统计、错误率统计、响应时间等
- Spring Cache 或 Redis:缓存淘汰策略
- SpringCloud Stream 或 Kafka:消息队列中的消费速率控制
- 分布式系统:优化一致性哈希问题
四.解题思路
使用单调队列(递减),实现滑动窗口的最大值获取;
先构造单调队列的数据结构,成员变量使用LinkedList,方法包含push(),pop(),max()这三个函数,
方法描述请看如下:
具体步骤请查看每个关键函数的代码注释
public class MonotonicQueue {
private final LinkedList<Integer> list = new LinkedList<>();
/**
* 判断列表不为空 & 链表的最新值小于n,则弹出这个最新值
*/
public void push(int n) {
while (!list.isEmpty() && list.getLast() < n) {
list.pollLast();
}
list.addLast(n);
}
/**
* 弹出最旧的值,但是要先判断这个旧值是否已经被弹出了(比如push方法中已被弹出),否则不做处理
*/
public void pop(int n) {
if (n == list.getFirst()) {
list.pollFirst();
}
}
/**
* 获取最旧的值(即队列头值),就是最大的值
*/
public int max() {
return list.getFirst();
}
}
五.完整题解
具体步骤请查看每个关键步骤的代码注释
public static int[] maxSlidingWindow(int[] nums, int k) {
// 定义返回结果
List<Integer> res = new ArrayList<>();
// 定义单调队列
MonotonicQueue queue = new MonotonicQueue();
for (int i = 0; i < nums.length; i++) {
// 先将k-1个窗口填满到单调队列
if (i < k - 1) {
queue.push(nums[i]);
} else {
// 推入窗口,此时当前窗口已满
queue.push(nums[i]);
// 获取当前窗口最大值,并加入到结果列表
int max = queue.max();
res.add(max);
// 删除当前窗口最旧的值,保证后续窗口还有余坐
queue.pop(nums[i - k + 1]);
}
}
// 将列表转换为数组,并返回
int[] arrRes = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
arrRes[i] = res.get(i);
}
return arrRes;
}