LeetCode每日一题-2.3-480-滑动窗口中位数C++

题目描述

在这里插入图片描述

思路 multiset

看到困难题,小萌新稍微想了一下想用之前求中位数的方法:大根堆和小根堆,但是代码是在是太长了,只是为了春招没必要那么卷,于是去找了multiset的解法。
set的本质是红黑树:平衡二叉搜索树。而multiset是可以有重复元素的set
由于对stl还处在一知半解的地步,昨晚还在想着set有什么用呢,今天就意识到了。
set里面的数字是可以用迭代器来获得的:配合prev和next

  • prev(迭代器,n)
    返回迭代器的前n个位置的迭代器。
  • next(迭代器,n)
    返回迭代器的后n个位置的迭代器。

这样就能指定一个位置,获得有序情况下的第n个数字
ps:迭代器指向的是空间,要获得元素得加上*
得到理所当然的代码

class Solution {
    
    
public:
    multiset<int> ms;
    double get(int& k){
    
    
        if(k%2) return *(next(ms.begin(), k/2));
        else return ((long long)(*(next(ms.begin(), k/2-1)))+(*next(ms.begin(), k/2))) * 0.5;
    }
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
    
    
        for(int i = 0; i < k; i++)ms.insert(nums[i]);
        vector<double> ans{
    
    get(k)};
        for(int i = k; i < nums.size(); i++){
    
    
            ms.insert(nums[i]);
            ms.erase(ms.find(nums[i-k]));
            ans.push_back(get(k));
        }
        return ans;
    }
};

在这里插入图片描述
击败9%的人,非常垃圾
时间复杂度O(K*(logK + K))
空间复杂度O(K)
然后就在前10%的题解里面找,清一色都是大根堆小根堆,然后眼前一亮!

// 优先队列
class Solution {
    
    
public:
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
    
    
        int n = nums.size();
        vector<double> medians;
        multiset<int> numset{
    
    nums.begin(), nums.begin()+k};
        auto mid = next(numset.begin(), k/2);
        for (int i = k; i <= n; i++) {
    
    
        	//如果是k&1=1说明是奇数,结果是(*mid + *mid)/2 = *mid 否则就是 (*mid + *(mid - 1))/2
            medians.push_back(((double)*mid + *(next(mid, (k&1) ? 0 : -1)))/2);
            //这样第一句最后可以再算一次
            if (i == n) break;
            numset.insert(nums[i]);
            if (nums[i] < *mid) {
    
    
                --mid;
            }
            if (nums[i-k] <= *mid) {
    
    
                ++mid;
            }
            numset.erase(numset.lower_bound(nums[i-k]));
        }
        return medians;
    }
};

在这里插入图片描述

好家伙,时间复杂度直接降到O(Klogk)
把调用next的时间变成了

if (nums[i] < *mid) 	--mid;
if (nums[i-k] <= *mid) 	++mid;

根据下一个数字的位置来决定mid迭代器如何维持在中间,省去了O(K)的复杂度取而代之O(1)。
通过这题我对迭代器也有了新的认识:能够指向一个容器的某一个位置,并且根据容器的元素类型的大小来移动自身。

猜你喜欢

转载自blog.csdn.net/qq_42883222/article/details/113617160