239. 滑动窗口最大值

给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

进阶:

你能在线性时间复杂度内解决此题吗?

示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:

滑动窗口的位置 最大值


[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7

提示:

1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
1 <= k <= nums.length

本题是道难题,难点就在于线性复杂度,我一开始没注意,用了优先队列来解本题,一开始先初始化把k个数存到优先队列里,然后每次迭代就把优先队列里最左边的数给取出来,每次都将队列队头的值给放到答案里即可,复杂度是log(N*log(k)) 超时了。
代码如下:

class Solution {
    static Comparator cmp = new Comparator() {
      public int compare(Integer e1, Integer e2) {
        return e2 - e1;
      }
    };
    public int[] maxSlidingWindow(int[] nums, int k) {
        
        Queue queue = new PriorityQueue<>(cmp);
        int ans [] = new int [nums.length-k+1];
        for (int i = 0; i < k; i++){
            queue.add(nums[i]);
        }
        int left = 0, right = k-1;
        while (right < nums.length){
            ans[left] = queue.peek();
            queue.remove(nums[left]);
            left++;
            right++;
            if(right < nums.length)
            queue.add(nums[right]);
        }
        return ans;
    }
}

因此得换个思路,看了题解才明白原来在此基础上优化一下即可,用一个双端队列即可。
从左往右遍历数组,维护一个最大大小为k的队列,每次遍历都将数字存到队列尾部,在此之前先将队列里所有小于该数的数字去处,因为以后再也不会用到他们了。这样就能保证每次在队头的一定是最大的元素,并且每次操作经过均摊,实现了O(N)的复杂度。
注意的是这次我们队列里存放的是下标,原因就在于我们需要剔除当队头的元素已经不在滑动窗口中,我们需要用下标进行处理。

代码如下:



class Solution {
    int k;
    public int[] maxSlidingWindow(int[] nums, int k) {
        this.k = k;
        ArrayDeque deq = new ArrayDeque<>();
        int ans [] = new int [nums.length-k+1];
        for (int i = 0; i < k; i++){
            clear(deq,nums,i);
            deq.addLast(i);
        }
        ans[0] = nums[deq.getFirst()];
        for( int i = k; i < nums.length; i++) {
            clear(deq,nums,i);
            deq.addLast(i);
            ans[i-k+1] = nums[deq.getFirst()];
        }
        return ans;
    }
    void clear (ArrayDeque deq,int[] nums,int i){
        
        while (!deq.isEmpty() && deq.getFirst() + k <= i) deq.removeFirst();

        while (!deq.isEmpty() && nums[deq.getLast()] < nums[i]) deq.removeLast();
    }
}

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sliding-window-maximum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

你可能感兴趣的:(239. 滑动窗口最大值)