给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
提示:
你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。
进阶:
你能在线性时间复杂度内解决此题吗?
思路一:
我自己的思路就是很暴力,利用一个链表来表示滑动窗口,通过入队和出队来控制大小和向后移动。同时编写一个函数用来求链表中数的最大值。
- 时间复杂度:O(k*n)
- 空间复杂度:O(k)
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length==0) return new int[0];
int[] res = new int[nums.length-k+1];
LinkedList<Integer> list = new LinkedList<Integer>();
for(int i=0;i<k;i++){
list.add(nums[i]);
}
for(int i=k;i<=nums.length;i++){
res[i-k] = maxNum(list);
list.remove(0);
if(i!=nums.length) list.add(nums[i]);
}
return res;
}
public int maxNum(List<Integer> list){
int max = Integer.MIN_VALUE;
for(int n:list){
if(n>max) max=n;
}
return max;
}
}
思路二:双端队列(不会)
双端队列和普通队列最大的不同在于,它允许我们在队列的头尾两端都能在 O(1)的时间内进行数据的查看、添加和删除。
与队列相似,我们可以利用一个双链表实现双端队列。双端队列最常用的地方就是实现一个长度动态变化的窗口或者连续区间,而动态窗口这种数据结构在很多题目里都有运用。
这道题而言,既然每次都要在一个移动的窗口中找到最大值,那很简单,我们就移动这个窗口,然后扫描一遍窗口获得最大值。假设数组里有 n个元素,这样的算法复杂度就是O(n∗k)。
那么我们能不能在移动窗口的过程中,更快地获得最大值呢?
可以利用一个双端队列来表示这个窗口。这个双端队列保存当前窗口中最大那个数的下标,双端队列新的头总是当前窗口中最大的那个数。
同时,有了这个下标,我们可以很快地知道新的窗口是否已经不再包含原来那个最大的数,如果不再包含,我们就把旧的数从双端队列的头删除。按照这样的操作,不管窗口的长度是多长,因为数组里的每个数都分别被压入和弹出双端队列一次,所以我们可以在 O(n) 的时间里完成任务。
思路三:动态规划
还是不会,罢了罢了。等回头再来看这个题吧。