[Leetcode] 480. Sliding Window Median 解题报告

题目

Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

Examples: 

[2,3,4] , the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

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. Your job is to output the median array for each window in the original array.

For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.

Window position                Median
---------------               -----
[1  3  -1] -3  5  3  6  7       1
 1 [3  -1  -3] 5  3  6  7       -1
 1  3 [-1  -3  5] 3  6  7       -1
 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]      6

Therefore, return the median sliding window as [1,-1,-1,3,5,6].

Note: 
You may assume k is always valid, ie: k is always smaller than input array's size for non-empty array.

思路

1、用两个multiset:我自己开始写了一个实现,思路是用两个multiset,其中一个保存移动窗口中一半小的数,另一个保存移动窗口中一半大的数。在窗口移动的过程中,可以用logk的时间对两个multiset进行调整,并且可以在O(1)的时间内获得当前移动窗口中的中位数。因此,整个代码的时间复杂度仍然是O(nlogk),空间复杂度是O(k)。

2、用一个multiset:后来看了网上的代码,只用了一个multiset。它的思路是在窗口移动的过程中,保持对指向中位数的迭代器的更新。这样代码就简洁很多了。当然时间复杂度仍然是O(nlogk)。

不得不承认,这就是菜鸟和高手的差距。

代码

1、用两个multiset:

class Solution {
public:
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        multiset<int> smaller, larger;
        vector<double> ans;
        for (int i = 0; i < nums.size(); ++i) {
            if (i >= k) {
                removeNum(smaller, larger, nums[i - k]);
            }
            addNum(smaller, larger, nums[i]);
            if (i + 1 >= k) {
                if (k % 2 != 0) {
                    ans.push_back(*smaller.rbegin());
                }
                else {
                    double v1 = static_cast<double>(*smaller.rbegin());
                    double v2 = static_cast<double>(*larger.begin());
                    ans.push_back((v1 + v2) / 2);
                }
            }
        }
        return ans;
    }
private:
    void addNum(multiset<int> &smaller, multiset<int> &larger, int num) {
        if (smaller.size() == larger.size()) {          // add to smaller
            smaller.insert(num);
        }
        else {                                          // add to larger
            larger.insert(num);
        }
        if (!smaller.empty() && !larger.empty() && *smaller.rbegin() > *larger.begin()) {
            int small = *smaller.rbegin(), large = *larger.begin();
            smaller.erase(--smaller.end());
            larger.erase(larger.begin());
            smaller.insert(large), larger.insert(small);
        }
    } 
    void removeNum(multiset<int> &smaller, multiset<int> &larger, int num) {
        if (!smaller.empty() && num <= *smaller.rbegin()) {     // remove from smaller
            auto it = smaller.find(num);
            if (it != smaller.end()) {
                smaller.erase(it);
            }
        }
        else if (!larger.empty()) {                             // remove from larger
            auto it = larger.find(num);
            if (it != larger.end()) {
                larger.erase(it);
            }
        }
        if (smaller.size() < larger.size()) {
            int value = *larger.begin();
            larger.erase(larger.begin());
            smaller.insert(value);
        }
    }
};

2、用一个multiset:

class Solution {
public:
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        multiset<int> window(nums.begin(), nums.begin() + k);
        auto mid = next(window.begin(), k / 2);
        vector<double> medians;
        for (int i = k; ; i++) {
            medians.push_back((double(*mid) + *prev(mid, 1 - k % 2)) / 2);      // Push the current median
            if (i == nums.size()) {                                             // If all done, return
                return medians;
            }
            window.insert(nums[i]);                                             // Insert nums[i]
            if (nums[i] < *mid) {
                --mid;
            }
            if (nums[i - k] <= *mid) {                                          // Erase nums[i-k].
                ++mid;
            }
            window.erase(window.lower_bound(nums[i-k]));
        }
        return medians;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值