LintCode 360: Sliding Window Median (双堆 或 双Set, 难题!)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/roufoo/article/details/86718973
  1. Sliding Window Median
    Given an array of n integer, and a moving window(size k), move the window at each iteration from the start of the array, find the median of the element inside the window at each moving. (If there are even numbers in the array, return the N/2-th number after sorting the element in the window. )

Example
For array [1,2,7,8,5], moving window size k = 3. return [2,7,7]

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

[ | 1,2,7 | ,8,5] , return the median 2;

then the window move one step forward.

[1, | 2,7,8 | ,5], return the median 7;

then the window move one step forward again.

[1,2, | 7,8,5 | ], return the median 7;

Challenge
O(nlog(n)) time

思路:
用双堆maxHeap或minHeap,分别装k/2左右的元素。同时维护一个sliding window,保证两个heap的总元素个数是K个。median就是minHeap的最后一个元素。

注意:

  1. JAVA的priorityqueue有erase(),但C++的priority_queue不提供erase()这个函数。所以只能用set。而有可能存在重复元素,故用multiset。
  2. 删除元素的时候要用erase(iterator)。因为虽然erase()也可以用元素值做参数,但有重复元素的话就把所有的重复元素都删掉了。
  3. set.end()是最后一个元素还往后一个,所以要得到set()的最后一个元素必须用set.rbegin(),好像也可以用–set.end()。但erase()的参数必须是值或iterator,所以不能用set.rbegin(),因为是reverse iterator。

代码如下:

class Solution {
public:
    /**
     * @param nums: A list of integers
     * @param k: An integer
     * @return: The median of the element inside the window at each moving
     */
    vector<int> medianSlidingWindow(vector<int> &nums, int k) {
            
        int len = nums.size();
        if ((len < k) || (k == 0)) return vector<int>();
        vector<int> result;
        multiset<int> smallSet, largetSet;
        
        for (int i = 0; i < len; ++i) {
            
            //make sure sum of smallSet.size() and largetSet.size() not exceeds k 
            if (i >= k) {
                //remove nums[i - k], sliding window 
                if (smallSet.find(nums[i - k]) != smallSet.end()) smallSet.erase(smallSet.find(nums[i - k]));
                else largetSet.erase(largetSet.find(nums[i - k]));
            }
            
            if (smallSet.size() <= largetSet.size()) { //try to insert into smallSet first
                if (largetSet.empty() || nums[i] <= *largetSet.begin()) {
                    smallSet.insert(nums[i]);
                } else {
                    smallSet.insert(*largetSet.begin());
                    largetSet.erase(largetSet.begin());
                    largetSet.insert(nums[i]);
                }
            } else { //try to insert into largetSet first
                //use .rbegin() to point to the last element, not .end() !!!   
                if (smallSet.empty() || nums[i] >= *smallSet.rbegin()) {
                    largetSet.insert(nums[i]);
                } else {
                    largetSet.insert(*smallSet.rbegin());
                    smallSet.erase(--smallSet.end());
                    smallSet.insert(nums[i]);
                }
            }
            
            if (i >= k - 1) {
                //int num = (k & 0x1) ? *smallSet.rbegin() : (*smallSet.rbegin() + *largetSet.begin()) / 2;
                result.push_back(*smallSet.rbegin());
            }
            
        }        
        return result;
    }
};

猜你喜欢

转载自blog.csdn.net/roufoo/article/details/86718973
今日推荐