import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param nums int整型一维数组 * @param k int整型 * @return int整型一维数组 */ /** 方法一:双向队列(链表) 时间复杂度O(n) 数学模拟居多 妙!!! */ public int[] minSlidingWindow(int[] nums, int k) { // deque存放的是元素的索引值,而不是元素!!! Deque<Integer> deque = new LinkedList<>(); int [] result = new int[nums.length - k + 1]; // 结果数组的索引 int index = 0; for (int i = 0; i < nums.length; i++) { // 移除已经不在窗口内的元素 if ((!deque.isEmpty()) && (deque.peekFirst() < i - k + 1)) { // peekFirst是返回队首元素,但不删除,pollFirst是要做删除操作 deque.pollFirst(); } // 移除窗口内比当前元素还要大的元素,因为肯定不是最小值,从队尾开始移除,保持元素的递增顺序 while ((!deque.isEmpty()) && (nums[deque.peekLast()] > nums[i])) { deque.pollLast(); } // 将当前元素索引添加到队尾 deque.offerLast(i); // 如果窗口长度已经到达k-1,说明可以找最小值了,比如i=2,k=3 if (i >= k - 1) { if (!deque.isEmpty()) { // 防止deque.peekFirst出现空指针异常 result[index++] = nums[deque.peekFirst()]; } } } return result; } /** 方法二:优先级队列 时间复杂度O(nlogk) k是堆的节点数 也就是窗口大小 比暴力解法还是好不少 */ public int[] minSlidingWindow(int[] nums, int k) { // 优先级队列 (小根堆,保存最小值) PriorityQueue<Integer> queue = new PriorityQueue<>(); // 窗口左边界 int left = 0; // 窗口右边界 int right = 0; // 结果数组索引 int index = 0; // 初始化操作 while (right < k) { queue.add(nums[right++]); } int[] result = new int[nums.length - k + 1]; // 初始化第一个最小值 if (!queue.isEmpty()) { result[index++] = queue.peek(); } // 当右边界小于数组长度时 while (right < nums.length) { // 窗口向右移动 先删除左边界的元素 queue.remove(nums[left]); // 左边界扩张 left++; // 添加新的右边界元素 queue.add(nums[right]); // 右边界扩张 right++; // 拿取此时小根堆的顶部元素 if (!queue.isEmpty()) { result[index++] = queue.peek(); } } return result; } }
本题知识点分析:
1.双向队列(链表)单调
2.优先级队列(小根堆,可以自定义,new Comparator就可以,建议Lambda表达式简写,(o1,o2)->(o2-o1)即可
3.数学模拟
4.队列存取
本题解题思路分析:
1.双向队列是方法一,数学模拟的思想居多,存储索引值,然后保持队列的递增特性,每次取出队首
2.优先级队列数学模拟就比较简单,缩减和扩展,小根堆内部排序,不用自己操作,唯一就是时间复杂度增加了
3.其他细节看注释就可以了,非常详细
本题使用编程语言: Java
建议大家还是多掌握几种做题的解法,暴力能不用就不用,因为面试的时候基本都是有要求的,暴力做出来大多数也是无用功,多用数据结构、常见API、算法类型、剪枝优化。
如果本篇文章对你有帮助的话,可以点个赞,有问题可以评论区留言,感谢支持~