C++描述 LeetCode 480. 滑动窗口中位数
大家好,我叫亓官劼(qí guān jié ),在CSDN中记录学习的点滴历程,时光荏苒,未来可期,加油~博主目前仅在CSDN中写博客,唯一博客更新的地址为:亓官劼的博客 ,同时正在尝试在B站中做一些内容分享,B站主页为: 亓官劼的B站主页
本文原创为亓官劼,请大家支持原创,部分平台一直在恶意盗取博主的文章!!!
若需联系博主,可以联系本人微信:qiguanjie2015
中位数是有序序列最中间的那个数。如果序列的大小是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。
例如:
[2,3,4]
,中位数是3
[2,3]
,中位数是(2 + 3) / 2 = 2.5
给你一个数组 nums,有一个大小为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。
示例:
给出 nums = [1,3,-1,-3,5,3,6,7]
,以及 k = 3。
窗口位置 中位数
--------------- -----
[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
因此,返回该滑动窗口的中位数数组 [1,-1,-1,3,5,6]
。
提示:
- 你可以假设
k
始终有效,即:k
始终小于输入的非空数组的元素个数。 - 与真实值误差在
10 ^ -5
以内的答案将被视作正确答案。
题解思路
这里一开始采用暴力解法,由于要保持原数列不变,所以每次取出当前的K个数,然后进行排序,去中位数,然后发现超时了。这里采用另一种求中位数的思路,就是我们使用划分来代替查找,因为我们只需要知道中间的数,而不需要K个数有序,以此来优化时间。这里要注意一下的是在K为偶数的时候,为了消除K为2时的边界问题,两个数采用s[k/2]和s[(k-1)/2]更方便
,不需要特殊处理边界。这里划分采用nth_element()
函数,此函数在STL库中。在此优化之后,卡线过关。有兴趣的也可以采用双优先队列+延迟删除来做,来进一步优化时间
算法实现
class Solution {
public:
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
vector<double> ans;
vector<int> s(k);
int r = nums.size() - k;
for(int i = 0 ; i <= r; i++){
for(int j = 0 ; j < k; j++){
s[j] = nums[i+j];
}
// sort(s.begin(),s.begin()+k);
if(k%2 == 1){
//k为奇数时,中间一项
// nth_element为划分函数,常用于找第k大的数
nth_element(s.begin(),s.begin()+k/2,s.begin()+k);
ans.push_back(s[k/2]);
}else{
// K为偶数时,中间两项,这里两项相加要先换成double,不然容易溢出
nth_element(s.begin(),s.begin()+k/2,s.begin()+k);
double mid = s[k/2];
nth_element(s.begin(),s.begin()+(k-1)/2,s.begin()+k);
ans.push_back((mid+s[(k-1)/2])/2.0);
}
}
return ans;
}
};