题目描述:
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口 k 内的数字。滑动窗口每次只向右移动一位。
返回滑动窗口最大值。
样例:
输入:[2, 3, 4, 2, 6, 2, 5, 1] , k=3
输出: [4, 4, 6, 6, 6, 5]
注意:
你可以假设 k 总是有效的,1 ≤ k ≤ 输入数组的大小,且输入数组不为空。
进阶:
你能在线性时间复杂度内解决此题吗?
分析:
暴力方法就是每次扫描当前滑动窗口的数值,得出最大解。所以时间复杂度是O(nk)。
第二种方法:
一个滑动窗口可以看成是一个队列,当窗口滑动时从该队列中移除一个元素,并加入新元素。因此要实现一个队列使得在在O(1)的时间内获取队列的最大值。该方法的时间复杂度是O(n)。
第三种方法,利用双端队列保存有可能成为滑动窗口最大值的元素的下标。
- 在队列不为空的情况下判断队列中的最后一个元素是否大于nums[i],如果不满足则将其pop,直到队尾元素大于nums[i]时结束;
- 然后将nums[i]的下标添加到队尾;
- 判断对头的最大值对应的下标是否还在当前滑动窗口的范围内,若已经不在即(max<i-k+1)则将其pop;滑动窗口区间[i-k+1,i]
- 当当前下标所对应的滑动窗口的起始下标大于等于0时,保存当前滑动窗口的最大值。
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums==null||nums.length<2)
return nums;
if(k<=0)
return null;
int []save=new int[nums.length-k+1];
LinkedList<Integer> list=new LinkedList<>();
//当i小于等于k时
for(int i=0;i<nums.length;i++) {
//确保队列中的下标对应的元素是按递减排序的(从队头到队尾)
while(!list.isEmpty()&&nums[list.peekLast()]<=nums[i])
list.pollLast();
//添加当前元素的下标到队列中
list.add(i);
//如果当前队列的最大值元素对应的下标已经不再相应的滑动窗口范围内将其pop
//i-k+1表示了滑动窗口的起始位置,i表示滑动窗口的结束位置
if(list.peek()<i-k+1)
list.poll();
//保存当前滑动窗口内的最大值
if(i-k+1>=0)
save[i-k+1]=nums[list.peek()];
}
return save;
}

博客围绕给定数组和滑动窗口大小 k,求滑动窗口最大值的问题展开。给出样例及注意事项,还提出进阶要求。分析了三种解法,暴力法时间复杂度为 O(nk),第二种用队列实现 O(1) 取最大值,时间复杂度 O(n),第三种利用双端队列保存元素下标求解。
734

被折叠的 条评论
为什么被折叠?



