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

来源:互联网 发布:护肤品行业数据 编辑:程序博客网 时间:2024/05/18 19:40

题目

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;    }};

原创粉丝点击