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: 1 ≤ k ≤ input array's size for non-empty array.

这道题给了我们一个数组,还是滑动窗口的大小,让我们求滑动窗口的中位数。我想起来之前也有一道滑动窗口的题Sliding Window Maximum,于是想套用那道题的方法,可以用deque怎么也做不出,因为求中位数并不是像求最大值那样只操作deque的首尾元素。后来看到了史蒂芬大神的方法,原来是要用一个multiset集合,和一个指向最中间元素的iterator。我们首先将数组的前k个数组加入集合中,由于multiset自带排序功能,所以我们通过k/2能快速的找到指向最中间的数字的迭代器mid,如果k为奇数,那么mid指向的数字就是中位数;如果k为偶数,那么mid指向的数跟前面那个数求平均值就是中位数。当我们添加新的数字到集合中,multiset会根据新数字的大小加到正确的位置,然后我们看如果这个新加入的数字比之前的mid指向的数小,那么中位数肯定被拉低了,所以mid往前移动一个,再看如果要删掉的数小于等于mid指向的数(注意这里加等号是因为要删的数可能就是mid指向的数),则mid向后移动一个。然后我们将滑动窗口最左边的数删掉,我们不能直接根据值来用erase来删数字,因为这样有可能删掉多个相同的数字,而是应该用lower_bound来找到第一个不小于目标值的数,通过iterator来删掉确定的一个数字,参见代码如下:

解法一:

class Solution {
public:
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
vector<double> res;
multiset<double> ms(nums.begin(), nums.begin() + k);
auto mid = next(ms.begin(), k / );
for (int i = k; ; ++i) {
res.push_back((*mid + *prev(mid, - k % )) / );
if (i == nums.size()) return res;
ms.insert(nums[i]);
if (nums[i] < *mid) --mid;
if (nums[i - k] <= *mid) ++mid;
ms.erase(ms.lower_bound(nums[i - k]));
}
}
};

上面的方法用到了很多STL内置的函数,比如next,lower_bound啥的,下面我们来看一种不使用这些函数的解法。这种解法跟Find Median from Data Stream那题的解法很类似,都是维护了small和large两个堆,分别保存有序数组的左半段和右半段的数字,保持small的长度大于等于large的长度。我们开始遍历数组nums,如果i>=k,说明此时滑动窗口已经满k个了,再滑动就要删掉最左值了,我们分别在small和large中查找最左值,有的话就删掉。然后处理增加数字的情况(分两种情况:1.如果small的长度小于large的长度,再看如果large是空或者新加的数小于等于large的首元素,我们把此数加入small中。否则就把large的首元素移出并加入small中,然后把新数字加入large。2.如果small的长度大于large,再看如果新数字大于small的尾元素,那么新数字加入large中,否则就把small的尾元素移出并加入large中,把新数字加入small中)。最后我们再计算中位数并加入结果res中,根据k的奇偶性来分别处理,参见代码如下:

解法二:

class Solution {
public:
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
vector<double> res;
multiset<int> small, large;
for (int i = ; i < nums.size(); ++i) {
if (i >= k) {
if (small.count(nums[i - k])) small.erase(small.find(nums[i - k]));
else if (large.count(nums[i - k])) large.erase(large.find(nums[i - k]));
}
if (small.size() <= large.size()) {
if (large.empty() || nums[i] <= *large.begin()) small.insert(nums[i]);
else {
small.insert(*large.begin());
large.erase(large.begin());
large.insert(nums[i]);
}
} else {
if (nums[i] >= *small.rbegin()) large.insert(nums[i]);
else {
large.insert(*small.rbegin());
small.erase(--small.end());
small.insert(nums[i]);
}
}
if (i >= (k - )) {
if (k % ) res.push_back(*small.rbegin());
else res.push_back(((double)*small.rbegin() + *large.begin()) / );
}
}
return res;
}
};

类似题目:

Find Median from Data Stream

Sliding Window Maximum

参考资料:

https://discuss.leetcode.com/topic/74905/c-o-n-logk-using-two-std-set

https://discuss.leetcode.com/topic/75160/easy-to-understand-clean-java-code

https://discuss.leetcode.com/topic/74963/o-n-log-k-c-using-multiset-and-updating-middle-iterator

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Sliding Window Median 滑动窗口中位数的更多相关文章

  1. 480 Sliding Window Median 滑动窗口中位数

    详见:https://leetcode.com/problems/sliding-window-median/description/ C++: class Solution { public: ve ...

  2. [LeetCode] Sliding Window Maximum 滑动窗口最大值

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  3. [LeetCode] 239. Sliding Window Maximum 滑动窗口最大值

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  4. [leetcode]239. Sliding Window Maximum滑动窗口最大值

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  5. POJ - 2823 Sliding Window (滑动窗口入门)

    An array of size n ≤ 10 6 is given to you. There is a sliding window of size kwhich is moving from t ...

  6. Sliding Window(滑动窗口)

    Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 58002   Accepted: 16616 Case Time Limi ...

  7. Leetcode: Sliding Window Median

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

  8. 239 Sliding Window Maximum 滑动窗口最大值

    给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口 k 内的数字.滑动窗口每次只向右移动一位.例如,给定 nums = [1,3,-1,-3, ...

  9. POJ 2823 Sliding Window (滑动窗口的最值问题 )

    Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 41264   Accepted: 12229 ...

随机推荐

  1. RabbitMQ 通信过程

    Rabbit MQ的通信过程 MQ全称为Message Queue, 是一种分布式应用程序的的通信方法,是消费-生产者模型的典型的代表,producer往消息队列中不断写入消息,而另一端consume ...

  2. 【Android】带进度条的WebView

    http://www.cnblogs.com/over140/archive/2013/03/07/2947721.html

  3. Spring MVC的handlermapping之RequestMappingHandlerMapping初始化

    RequestMappingHandlerMapping:这个handlerMapping是基于注解的同样,先上类图: 通过类图可以看到,同样是继承父类 AbstractHandlerMapping来 ...

  4. curl的使用基本流程,HTTP的get请求,post请求

    使用CURL的PHP扩展完成一个HTTP请求的发送一般有以下几个步骤: 1.初始化连接句柄: 2.设置CURL选项: 3.执行并获取结果: 4.释放VURL连接句柄. 下面的程序片段是使用CURL发送 ...

  5. Git常用命令(二)------ 远程库操作

    本文总结自廖雪峰网站. Git支持多种协议,git://使用ssh协议,速度最快,也可使用https等协议. 对远程库操作: 推送: 1.先远程建立一个Repo库,f 2.远程和本地关联: git r ...

  6. django restful 1-在线Python编辑器

    客户端(浏览器)----> 前端页面-----> 后端处理数据,并把数据以 json 形式发送到前端 online_app.py from django.conf import setti ...

  7. codves 3044 矩形面积求并

    codves  3044 矩形面积求并  题目等级 : 钻石 Diamond 题目描述 Description 输入n个矩形,求他们总共占地面积(也就是求一下面积的并) 输入描述 Input Desc ...

  8. NYOJ 炫舞家st

    #include <iostream>#include <cstring>#include <algorithm>using namespace std; cons ...

  9. 数据结构与算法 —— 链表linked list(01)

    链表(维基百科) 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer).由于不必须按顺序存储, ...

  10. LightningChart最新版 v.8.3 全新发布,新功能使用教程。

    LightningChart最新版v.8.3全新发布,主要介绍以下五个新功能及使用教程.   1. 网格模型,三角鼠标追踪 Tracing MeshModels with mouse. Traced ...