1. 程式人生 > >[LeetCode] Sliding Window Maximum 滑動視窗最大值

[LeetCode] 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,讓我們每次向右滑動一個數字,每次返回視窗內的數字的最大值,而且要求我們程式碼的時間複雜度為O(n)。提示我們要用雙向佇列deque來解題,並提示我們視窗中只留下有用的值,沒用的全移除掉。果然Hard的題目我就是不會做,網上看到了別人的解法才明白,解法又巧妙有簡潔,膜拜啊。大概思路是用雙向佇列儲存數字的下標,遍歷整個陣列,如果此時佇列的首元素是i - k的話,表示此時視窗向右移了一步,則移除隊首元素。然後比較隊尾元素和將要進來的值,如果小的話就都移除,然後此時我們把隊首元素加入結果中即可,參見程式碼如下:

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;
    }
};

參考資料: