• LeetCode239. Sliding Window Maximum


    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 the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.

    Example:

    Input: nums = [1,3,-1,-3,5,3,6,7], and k = 3
    Output: [3,3,5,5,6,7] 
    Explanation: 
    
    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
    

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

    Follow up:
    Could you solve it in linear time?

    思路

    咋一看不知道题目要干嘛,其实求的是窗口从左往右滑动过程中,返回窗口中元素的最大值。比如上面Max的那一列是 3 3 5 5 6 7,那么返回的就是这个。

    感觉直接遍历好像就可以了诶,不过应该会超时。而且提示我们用O(n)复杂度内解题了,看了下别人的解法,使用的是双向队列deque,保存数组元素的索引,遍历整个数组。

    We scan the array from 0 to n-1, keep "promising" elements in the deque. The algorithm is amortized O(n) as each element is put and polled once.

    At each i, we keep "promising" elements, which are potentially max number in window [i-(k-1),i] or any subsequent window. This means

    1.  If an element in the deque and it is out of i-(k-1), we discard them. We just need to poll from the head, as we are using a deque and elements are ordered as the sequence in the array

    2.  Now only those elements within [i-(k-1),i] are in the deque. We then discard elements smaller than a[i] from the tail. This is because if a[x] <a[i] and x<i, then a[x] has no chance to be the "max" in [i-(k-1),i], or any other subsequent window: a[i] would always be a better candidate.

    3.  As a result elements in the deque are ordered in both sequence in array and their value. At each step the head of the deque is the max element in [i-(k-1),i]

    对于每个索引i位置,它都有可能是窗口[i-(k-1),i]中的那个最大值,以题目中的例子来说明,假如i=4, 那么窗口[2, 4],即索引 2,3,4位置构成的窗口。位置4可能是这个窗口中的最大值,或者是后面窗口的最大值(因为向右滑动时还包含在里面)。这表明:

    1. 如果当前队列中的索引不在窗口[2, 4]的范围内,那么丢弃它。

    2. 如果现在队列中的索引只有当前窗口里面[i-(k-1),i]的,那么从尾部开始丢弃掉比a[i]小的元素,这是因为如果 a[x]<a[i] 并且 x<i,那么a[x] 不可能是 [i-(k-1), i] 中的最大值,并且在后面的窗口中也不可能是最大的,因为a[i]是更好的选择。(因为当前的索引,也就是从 i-(k-1)到i都被限制在一个窗口里了)

    3. 因为每次的滑动窗口所选择的出的最大元素在队列中是按照他们的数组索引和值排序的,所以每一不这个deque的头就是 [i-(k-1),i] 中的最大元素。

    代码

    public int[] maxSlidingWindow(int[] a, int k) {        
            if (a == null || k <= 0) {
                return new int[0];
            }
            int n = a.length;
            int[] r = new int[n-k+1];
            int ri = 0;
            // store index
            Deque<Integer> q = new ArrayDeque<>(); //双端队列的用法
            for (int i = 0; i < a.length; i++) {
                // 将不在当前窗口 i-k+1 到 i 内的索引移除
                while (!q.isEmpty() && q.peek() < i - k + 1) { 
                    q.poll(); // 弹出队列中的第一元素(头部,最左边)
                }
                // 从尾部(队列右边)remove smaller numbers in k range as they are useless
                while (!q.isEmpty() && a[q.peekLast()] < a[i]) {
                    q.pollLast();
                }
                // q contains index... r contains content
                q.offer(i);
                if (i >= k - 1) {  // 只需要判断i-k+1>0即可,因为只有一开始不够k个元素
                    r[ri++] = a[q.peek()]; // 经过上面处理,队头是当前窗口中的最大元素
                }
            }
            return r;
        }
  • 相关阅读:
    我的后端开发书架2015 2.0版
    Java根据字节数据判断文件类型
    基于lucene的案例开发:查询语句创建PackQuery
    Web 前沿——HTML5 Form Data 对象的使用
    基于HTML5的可预览多图片Ajax上传
    【面试】Spring问答Top 25
    【劳动节江南白衣Calvin 】我的后端开发书架2015
    【转载】Java 动态代理
    使用iframe给页面的localStorage扩容
    js中的||和&&使用技巧
  • 原文地址:https://www.cnblogs.com/f91og/p/9465799.html
Copyright © 2020-2023  润新知