[LeetCode]239. Sliding Window Maximum

滑动窗口,multiset使用

Posted by JinFei on March 25, 2020

题目描述

  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.

Follow up:

Could you solve it in linear time?

Example1:

  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

Follow up:

  • 1 <= nums.length <= 10^5
  • 10^4 <= nums[i] <= 10^4
  • 1 <= k <= nums.length

解题思路

  • 参考
  • 我们希望窗口内的数字是有序的,但是每次给新窗口排序又太费时了,所以最好能有一种类似二叉搜索树的结构,可以在 lgn 的时间复杂度内完成插入和删除操作,那么使用 STL 自带的 multiset 就能满足我们的需求,这是一种基于红黑树的数据结构,可以自动对元素进行排序,又允许有重复值,完美契合
  • 遍历每个数字,即窗口右移,若超过了k,则需要把左边界值删除,这里不能直接删除 nums[i-k],因为集合中可能有重复数字,我们只想删除一个,而 erase 默认是将所有和目标值相同的元素都删掉,所以我们只能提供一个 iterator,代表一个确定的删除位置,先通过 find() 函数找到左边界 nums[i-k] 在集合中的位置,再删除即可。
  • 然后将当前数字插入到集合中,此时看若 i >= k-1,说明窗口大小正好是k,就需要将最大值加入结果 res 中,而由于 multiset 是按升序排列的,最大值在最后一个元素,我们可以通过 rbegin() 来取出
class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        multiset<int> sets;
        vector<int> res;
        for(int i = 0; i < nums.size(); i++){
            if(i >= k){ // 如果 i >= k 的话,证明需要移除左边的,不能直接进行溢出定值,需要一个迭代器
                sets.erase(sets.find(nums[i - k]));
            }
            sets.insert(nums[i]);   // 插入
            if(i >= k - 1){
                res.push_back(*sets.rbegin()); // set是按key升序排序的,那么最后一个rbegin指向的就是最大的元素
            }
        }
        return res;
    }
};