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. 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?

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.

方法0: brute force

Complexity

Time complexity: O((n - k + 1)n), which is O(n2) at its worst case k = n / 2
Space complexity: O(1)

Iterator:

// Author: Huahua
// Running time: 180 ms
class Solution {
public:
  vector<int> maxSlidingWindow(vector<int>& nums, int k) {    
    vector<int> ans;
    for (int i = k - 1; i < nums.size(); ++i) {
      ans.push_back(*max_element(nums.begin() + i - k + 1, nums.begin() + i + 1));
    }
    return ans;
  }
};

Index:

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        if (nums.empty()) return {};
        int n = nums.size();
        vector<int> result;
        for (int i = k - 1; i < n; i++){
            int mx = INT_MIN;
            for (int j = 0; j < k; j++){
                mx = max(mx, nums[i - j]);
            }
            result.push_back(mx);
        }
        return result;
    }
};

方法1: deque

思路:

在这里插入图片描述

vector只支持pop_back, push_back, 不支持pop_front, push_front, 而deque同时支持前后。之前从vector前面删除是利用iterator,代价也比较高。deque的特点包括:

  1. 只是多了从前面插入和删除,并且O(1),其他interface几乎一样
  2. 在内存里不一定是连续储存
  3. https://www.geeksforgeeks.org/difference-between-stdremove-and-vectorerase-for-vectors/.

下面这个方法在deque中存入的实际是每个数的坐标,这样能使deque中的数和nums中的对应起来。“It’s more handy to store in the deque indexes instead of elements since both are used during an array parsing”. 每当进队一个数需要如下逻辑:1. 队列是否为空,是的话可以直接进队,2. 如果对列不为空,取将q中所有比nums[i] 小的数字从后往前pop_back(),3,检查front是否已经过期:q.front == i - k,因为此时的sliding window只包含 i - k + 1 到 i, 4. nums[i] 入栈push_back, 5. 如果在 i - k + 1 >= 0 的范围内,此时可以推入q.front()作为结果。

官方题解:在这里插入图片描述

易错点

  1. 第三步的检查不太在乎顺序,只要保证过期元素不会被最后一步推进结果
  2. 先pop_back()和push_back的顺序必须遵守

Complexity

Time complexity: O(n)
Space complexity: O(n)

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        if (nums.empty()) return {};
        int n = nums.size();
        vector<int> result;
        deque<int> q;
        for (int i = 0; i < n; 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 >= 0) {
                result.push_back(nums[q.front()]);
            }
        }
        return result;
    }
};

// [1,3,-1,-3,5,3,6,7]

二刷:

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

方法2: heap

discussion: https://leetcode.com/problems/sliding-window-maximum/discuss/65999/3-C%2B%2B-Solutions

思路:

用multiset保持k个元素sorted。

易错点

在这里插入图片描述

Complexity

Time complexity: O(nlogk)
Space complexity: O(k)

vector<int> maxSlidingWindow(vector<int>& nums, int k) {
    vector<int> result;
    if (k == 0) return result;
    multiset<int> w;
    for (int i = 0, n = (int)nums.size(); i < n; i++) {
        if (i >= k)
            w.erase(w.find(nums[i-k]));
        w.insert(nums[i]);
        if (i >= k-1)
            result.push_back(*w.rbegin());
    }
    return result;
}

方法3: dynamic programming

官方题解:https://leetcode.com/problems/sliding-window-maximum/solution/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值