题目链接:. - 力扣(LeetCode)
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
进阶:
你能在线性时间复杂度内解决此题吗?
提示:
- 1 <= nums.length <= 10^5
- -10^4 <= nums[i] <= 10^4
- 1 <= k <= nums.length
首先求最大值方法有很多 但是不管是优先队列还是暴力遍历都不能很好满足题目需求 我们需要一个新的数据结构——单调递减队列
为什么呢?
因为在窗口滑动期间 我们需要的是窗口范围内的最大数值 我们需要一种队列既能维护范围内的最大数值同时可以对不符合要求的数值进行去除 为了满足题目要求我们才需要自定义单调递减队列
那么什么是单调递减队列?
在窗口移动的过程中 元素被依次放入队列 规定头部元素到尾部元素按从大到小依次排序 当要加入的元素比尾部元素小时才可以加入队列成为新的队列尾部 否则要先去除尾部较小的元素直到尾部元素大于要加入的元素
自定义的单调递减队列:
public class MontonicQueue {
private LinkedList<Integer> deque=new LinkedList<>();
public Integer peek(){
return deque.peekFirst();
}
public void poll(){
deque.pollFirst();
}
public void offer(Integer val){
while (!deque.isEmpty()&&deque.peekLast()<val){
deque.pollLast();
}
deque.offerLast(val);
}
@Override
public String toString() {
return deque.toString();
}
}
重点的是offer方法 大家可以看看逻辑 和上述讲的单调递减队列逻辑是一样的
public static int[] maxSlidingWindow(int[] nums, int k) {
MontonicQueue queue = new MontonicQueue(); //单调递减队列
ArrayList<Integer> list = new ArrayList<>(); //集合用来存放每次窗口滑动的最大值
for (int i = 0; i < nums.length; i++) {
if (i >= k && nums[i - k] == queue.peek()) { //这个判断条件是因为防止 当出现像1, 3, -1, -3,-4, 5, 3 的情况
queue.poll(); //因为当窗口右侧到达-4时 整个队列的数值是 3, -1, -3,-4 超过规定窗口的个数3 最大值还是3 而不是-1
}
queue.offer(nums[i]); //调用offer方法
if (i >= (k - 1)) { //大家可以打印试试 如果没有这条件会多打印开头的值 因为队列是从0开始遍历的 一开始不满足队列个数是3
//System.out.println(queue.peek());
list.add(queue.peek());
}
}
return list.stream().mapToInt(Integer::intValue).toArray(); }
/*这段Java代码是对一个Integer类型的List进行流式操作:
1. list.stream():调用Java 8引入的Stream API,将List转换为Stream流。Stream流是一种可以从支持数据处理管道的概念中受益的数据序列,它支持连续和并行聚集操作。
2. .mapToInt(Integer::intValue):这是一个映射操作,它将Stream中的每个元素转换为其对应的int值。在这里,使用了方法引用`Integer::intValue`,作用是将Integer对象转换为它的原始int值。
3. .toArray():这个操作将映射后的IntStream转换为一个int数组。所有的Integer元素现在都已经转换成了int类型,并存储在一个新的数组中。
总的来说,这段代码就是将一个Integer类型的List转换为一个int类型的数组,转换的过程中使用了Java 8的Stream API进行操作,提高了代码的简洁性和效率。 * */
但使用单调递减队列 整道题的思路就比较简单