• [LeetCode] 239. 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.

    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, 1 ≤ k ≤ input array's size.

    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.

    给一个数组和大小为k的窗口,窗口每次向右移动1位,返回每次窗口中的最大值。

    解法1: 优先队列Priority Queue,维护一个大小为K的最大堆,每向右移动1位,都把堆中上一个窗口中最左边的数扔掉,再把新数加入堆中,这样堆顶就是这个窗口内最大的值。T: O(nlogk) ,S:O(k)

    解法:根据提示,要求用线性的时间复杂度,用deque数据结构。当右移遇到新数时,将新数和双向队列的末尾比较,如果末尾比新数小,则把末尾扔掉,直到该队列的末尾比新数大或者队列为空的时候才停止。这样就保证了队列里的元素是从头到尾降序的,而且只有窗口内的数。保持队列里只有窗口内数,也是每来一个新数就把窗口最左边的扔掉,然后把新的加进去。然而在加新数的时候,已经把很多没用的数给扔了,这样队列头部的数并不一定是窗口最左边的数。这里的技巧是,队列中存的是数的下标,这样既可以得到数的值,也可以知道是不是窗口最左边的数。T: O(n), S: O(k)

    Java: Priority Queue

    public class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {
            if(nums == null || nums.length == 0) return new int[0];
            PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder());
            int[] res = new int[nums.length + 1 - k];
            for(int i = 0; i < nums.length; i++){
                // 把窗口最左边的数去掉
                if(i >= k) pq.remove(nums[i - k]);
                // 把新的数加入窗口的堆中
                pq.offer(nums[i]);
                // 堆顶就是窗口的最大值
                if(i + 1 >= k) res[i + 1 - k] = pq.peek();
            }
            return res;
        }
    }

    Java:

    public class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {
            if(nums == null || nums.length == 0) return new int[0];
            LinkedList<Integer> deque = new LinkedList<Integer>();
            int[] res = new int[nums.length + 1 - k];
            for(int i = 0; i < nums.length; i++){
                // 每当新数进来时,如果发现队列头部的数的下标,是窗口最左边数的下标,则扔掉
                if(!deque.isEmpty() && deque.peekFirst() == i - k) deque.poll();
                // 把队列尾部所有比新数小的都扔掉,保证队列是降序的
                while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) deque.removeLast();
                // 加入新数
                deque.offerLast(i);
                // 队列头部就是该窗口内第一大的
                if((i + 1) >= k) res[i + 1 - k] = nums[deque.peek()];
            }
            return res;
        }
    }  

    Java: Time Complexity - O(n), Space Complexity - O(k)

    public class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {
            if(nums == null || nums.length == 0)
                return new int[]{};
            int len = nums.length;
            int[] res = new int[len - k + 1];
            Deque<Integer> dq = new LinkedList<>();         
            
            for(int i = 0; i < len; i++) {
                while(!dq.isEmpty() && dq.peekFirst() < i - (k - 1))    // maintain a window of length k
                    dq.pollFirst();
                
                while(!dq.isEmpty() && nums[dq.peekLast()] < nums[i])  // compare last elements with nums[i]
                    dq.pollLast();
                    
                dq.offerLast(i);
                
                if(i >= k - 1)
                    res[i - (k - 1)] = nums[dq.peekFirst()];    // since we have a descendent deque, first is always the largest in window
            }
            
            return res;
        }
    }
    

    Java: Time Complexity - O(n), Space Complexity - O(k)

    public class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {
            if (nums == null || nums.length < k || k <= 0) return nums;
            int len = nums.length;
            int[] res = new int[len - k + 1];
            LinkedList<Integer> window = new LinkedList<>();
            for (int i = 0; i < len; i++) {
                if (!window.isEmpty() && window.peekFirst() <= i - k) window.pollFirst();
                while (!window.isEmpty() && nums[window.peekLast()] < nums[i]) window.pollLast();
                window.offerLast(i);
                if (i - (k - 1) >= 0) res[i - (k - 1)] = nums[window.peek()];
            }
            return res;
        }
    }    

    Python:

    from collections import deque
    
    class Solution(object):
        def maxSlidingWindow(self, nums, k):
            """
            :type nums: List[int]
            :type k: int
            :rtype: List[int]
            """
            dq = deque()
            max_numbers = []
    
            for i in xrange(len(nums)):
                while dq and nums[i] >= nums[dq[-1]]:
                    dq.pop()
                dq.append(i)
                if i >= k and dq and dq[0] <= i - k:
                    dq.popleft()
                if i >= k - 1:
                    max_numbers.append(nums[dq[0]])
    
            return max_numbers
    

    C++:

    class Solution {
    public:
        vector<int> maxSlidingWindow(vector<int>& nums, int k) {
            vector<int> res;
            deque<int> q;
            for (int i = 0; i < nums.size(); ++i) {
                if (!q.empty() && q.front() == i - k) q.pop_front();
                while (!q.empty() && nums[q.back()] < nums[i]) q.pop_back();
                q.push_back(i);
                if (i >= k - 1) res.push_back(nums[q.front()]);
            }
            return res;
        }
    };
    

    C++:

    class Solution {
    public:
        vector<int> maxSlidingWindow(vector<int>& nums, int k) {
            deque<int> dq;
            vector<int> max_numbers;
    
            for (int i = 0; i < nums.size(); ++i) {
                while (!dq.empty() && nums[i] >= nums[dq.back()]) {
                    dq.pop_back();
                }
                dq.emplace_back(i);
                if (i >= k && !dq.empty() && dq.front() == i - k) {
                    dq.pop_front();
                }
                if (i >= k - 1) {
                    max_numbers.emplace_back(nums[dq.front()]);
                }
            }
    
            return max_numbers;
        }
    };
    

      

        

    All LeetCode Questions List 题目汇总

  • 相关阅读:
    接水果(fruit)——整体二分+扫描线
    大融合——LCT维护子树信息
    魔卡少女(cardcaptor)——线段树
    而立之年的一些人生感悟
    PHP 输出缓冲控制(Output Control) 学习
    我所了解的cgi
    c语言指针学习
    ubuntu 安装 zend studio
    Zend_Controller_Front 研究
    php autoload 笔记
  • 原文地址:https://www.cnblogs.com/lightwindy/p/8661524.html
Copyright © 2020-2023  润新知