[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 題目匯總


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM