LintCode 362: Sliding Window Maximum (单调队列经典题!)

Description
Given an array of n integer with duplicate number, and a moving window(size k), move the window at each iteration from the start of the array, find the maximum number inside the window at each moving.

Have you met this question in a real interview?
Example
For array [1, 2, 7, 7, 8], moving window size k = 3. return [7, 7, 8]

At first the window is at the start of the array like this

[|1, 2, 7| ,7, 8] , return the maximum 7;

then the window move one step forward.

[1, |2, 7 ,7|, 8], return the maximum 7;

then the window move one step forward again.

[1, 2, |7, 7, 8|], return the maximum 8;

Challenge
o(n) time and O(k) memory

最好的解法应该是用单调递减队列,因为是求最大值(如果求最小值用单调递增对列)。这里递减是说从deque的front()到back()递减。
注意判断条件:

  1. (nums[i] > nums[dq.back()]) 适用于单调递减队列
    而 (nums[i] < nums[dq.back()]) 适用于单调递增队列
  2. (i - dq.front() == k) 用来决定pop掉front()的元素。注意不能用dq.size()==k,因为有些元素已经在最开始的while()循环就pop_back,所以没有算进window size,结果当然不对。
class Solution {
public:
    /**
     * @param nums: A list of integers.
     * @param k: An integer
     * @return: The maximum number inside the window at each moving.
     */
    vector<int> maxSlidingWindow(vector<int> &nums, int k) {
        
        int len = nums.size();
        vector<int> result;
        if ((len <= 0) || (len < k)) return result;
        
        deque<int> dq; // non-increasing list, as it needs maximum (otherwise, non-decreasing list for minimum)

        for (int i = 0; i < len; ++i) {

            while (!dq.empty() && (nums[i] > nums[dq.back()]))  {  //for non-increasing, use > here; for non-decreasing, use < here
                dq.pop_back();
            }

            dq.push_back(i);

            if (i - dq.front() == k) {
                dq.pop_front();
            }
            
            if (i >= k - 1) {
                result.push_back(nums[dq.front()]);
            }
        }
        
        return result;
    }
};

注意,下面这种写法是错误的:

        for (int i = 0; i < len; ++i) {
            while (!dq.empty() && nums[i] > dq.back())  {  //for non-increasing, use > here; for non-decreasing, use < here
                dq.pop_back();
            }
            dq.push_back(nums[i]);
            if (dq.size() == k) { //wrong!!!
                result.push_back(dq.front());
                dq.pop_front();
            }
        }

因为dq.size()==k并不能保证window size = k, 因为有些元素已经删掉了。所以dq里面一定要保存元素在原数组中的index!

注意:
如果是求滑动窗口移动过程中的的窗口sum的最大值,则不需要用单调队列,直接用更新maxSum即可,代码如下:

    int maxFixSizeSubArray(vector<int> & nums, int k) {
        int n = nums.size();
        if (n < k) return 0;
        int sum = 0, maxSum = 0;
        for (int i = 0; i < k; ++i) {
            sum += nums[i];
        }
        maxSum = sum;
        for (int i = 1; i < n - k + 1; ++i) {
            sum += nums[k + i - 1] - nums[i - 1];
            maxSum = max(maxSum, sum);
        }
        return maxSum;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值