Sliding Window Maximum

本文介绍了一种求解滑动窗口最大值的高效算法,使用双端队列(deque)来保持窗口内的元素,并确保队列内的元素按值降序排列。通过这种方式,可以在O(N)的时间复杂度内解决问题。此外,还提供了一种使用优先队列(最大堆)的解决方案,该方法的时间复杂度为O(N log K)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see thek numbers in the window. Each time the sliding window moves right by one position.

For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.

Window position                Max
---------------               -----
[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

Therefore, return the max sliding window as [3,3,5,5,6,7].

Note: 
You may assume k is always valid, ie: 1 ≤ k ≤ input array's size for non-empty array.

Follow up:
Could you solve it in linear time?

Hint:

  1. How about using a data structure such as deque (double-ended queue)?
  2. The queue size need not be the same as the window’s size.
  3. Remove redundant elements and the queue should store only elements that need to be considered.

思路:发现单调栈的性质,因为如果4,8 那么,4是没必要存的,那么stack里面存单调当前的最大值,如果发现后面进来的元素比末尾的大,把末尾的一直踢走,也就是踢走4,一直踢到没有比他大为止,那么就是个单调递减的序列,但是这个窗口还在滑动,也就是前面的值要踢走,那么前面要出,后面要进,还要后面还要动态弹出去,前后都出去的数据结构就是deque。O(N)

8,4为什么要keep 4,也就是4是最大值的candidate,因为8走了,4可能成大王;

所有这种k window的题目,可以首先收集 [0 ~ k -2] 的元素,然后从第k个开始,开始计算;

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums == null || nums.length == 0) {
            return nums;
        }
        Deque<Integer> deque = new ArrayDeque<Integer>();
        int n = nums.length;
        int[] res = new int[n - k + 1];
        int index = 0;
        for(int i = 0; i < nums.length; i++) {
            if(i < k - 1) {
                inqueue(deque, nums, i);
            } else {
                // i >= k - 1;
                inqueue(deque, nums, i);
                res[index++] = nums[deque.peekFirst()];
                dequeue(deque, nums, i - k + 1);
            }
        }
        return res;
    }
    
    private void inqueue(Deque<Integer> deque, int[] nums, int pos) {
        while(!deque.isEmpty() && nums[deque.peekLast()] <= nums[pos]) {
            deque.pollLast();
        }
        deque.addLast(pos);
    }
    
    private void dequeue(Deque<Integer> deque, int[] nums, int pos) {
        if(!deque.isEmpty() && deque.peekFirst() == pos) {
            deque.pollFirst();
        }
    }
}

思路2:这题也可以用pq来做。nlogk. 维护一个大小为K的最大堆,依此维护一个大小为K的窗口,每次读入一个新数,都把堆中窗口最左边的数扔掉,再把新数加入堆中,这样堆顶就是这个窗口内最大的值. O(nlog(k))

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums == null || nums.length == 0 || k < 0) {
            return new int[0];
        }
        PriorityQueue<Integer> pq 
            = new PriorityQueue<Integer>(k, Collections.reverseOrder());
        int[] res = new int[nums.length - k + 1];
        int index = 0;
        for(int i = 0; i < nums.length; i++) {
            pq.offer(nums[i]);
            if(pq.size() == k) {
                res[index++] = pq.peek();
                pq.remove(nums[i - k + 1]);
            }
        }
        return res;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值