(Java算法)剑指offer-面试题59 - I. 滑动窗口的最大值

给定一个数组 nums 和滑动窗口的大小 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
 

提示:

你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。

本题采用双端队列的方法来完成,首先先介绍一下双端队列,Deque。这是一个接口,我们一般在使用的时候,都使用ArrayDeque,LinkedList,也就是说,一个是基于数组,一个是基于链表。他和普通的队列最大的区别就在于,双端队列从两端都可以进行队列的操作。

解题步骤:本题的目的是用长度为k的数组进行入队出队的操作,直到滑到最右边,然后将每次滑动产生的新数组内的最大值,存储到一个新的数组中,最后返回这个数组。

解题思路:我们可以将这个滑动的数组,翻译成一个双端队列。将每次将来进队的数字和队列最右边(队尾)进行比较,如果新数字大,就将队尾进行出队操作,新数进行入队操作。那么问题就来了,我们要如何知道新进来的数字,成为双向队列对头的时机呢,也可以说,我们如何让窗口和双向队列里面的数保持一致呢?这就可以用一个技巧。我们可以用队列不去存储value,而去存储在nums里面的下标,然后就可以判断这个数实际的下标了。

public int[] maxSlidingWindow(int[] nums, int k) {
        Deque<Integer> deque = new ArrayDeque<>();
        if(nums.length==0){
            return new int[0];
        }
        int arr[] = new int[nums.length-k+1];
        for(int i = 0 ; i<nums.length ; i++){
            if(!deque.isEmpty()&&deque.peekFirst()==i-k){
                deque.removeFirst();
            }
            while(!deque.isEmpty()&&nums[deque.peekLast()]<nums[i]){
                deque.removeLast();
            }
            deque.offerLast(i);
            if(i>=k-1){
                arr[i-k+1]=nums[deque.peek()];
            }
        }
        return arr;
    }
发布了313 篇原创文章 · 获赞 58 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41936805/article/details/104687320