寻找两个排序数组的中位数
来源:互联网 发布:w7怎么设置网络共享 编辑:程序博客网 时间:2024/06/04 08:38
寻找两个排序数组的中位数
中位数保持
从一组数字的中位数两边删除同样多的元素(不管被删除的数字的相对顺序是什么样的),中位数保持。— 尽可以把位于中位数左边和右边的这些数字打乱,只要中位数两边被删除的数目相等就能使中位数保持(是剩下的这些数的中位数)。
情景分析
- 假设两个已排序的数组,记为
A[m] ,B[n] 。设想一下,当能确定这两个数组中比中位数小的数值的个数x 以及比中位数大的数值的个数y 时,求出min=Min(x,y) ,那么同时去掉中位数两边(左边的数小于或等于中位数,右边的数大于或等于中位数)任意min 个数,中位数保持。为了便于描述,假设数组的起始坐标是1而不是0。还假设
C[m+n] 是将A和B组合起来排序了的数组。他的中位数下标记为c。记A的中位数的下标为a,B的中位数的下标为b。记A[a] 在C中的下标位置为Ca ,B[a] 在C中的下标位置为Cb 。首先,当
A[a]==B[b] 时,C的中位数就是A[a] ,看图。
位于两边的数的个数一定是相等的。然后,若
A[a]≠B[b] ,我们总有办法交换集合,使得集合A和B满足A[a]<B[b]
case1: m为奇数,n为奇数。
看图:
∵A[a]<B[b] ,那么一定有:
A[a] 在C中的下标位置Ca 最大能排在b所在位置Cb 的前面,所以有Ca≤a+b−1=m+12+(n+12−1)=m+n2=c ,于是,所有位于a左边的数均小于或等于c-1,均位于C的中位数的左边,他们的个数是m+12−1=m−12 。
B[b] 在C中的下标位置Cb 最小能排在a所在位置Ca 的后面,所以有Cb≥a+b=m+12+(n+12)=m+n2+1=c+1 ,所以A中位于橙色方框中的所有数都位于C的中位数的右边,他们的个数是n+12 。
接下来就需要求出Min(n+12 ,m−12) 。然后剔除A中的前Min(n+12 ,m−12) 个数,在B中剔除后Min(n+12 ,m−12) 个数。中位数保持。case2: m为偶数,n为偶数。
看图:
∵A[a]<B[b] ,那么一定有:
A[a] 在C中的下标位置Ca 最大能排在b所在位置Cb 的前面,所以有Ca≤a+b−1=m2+(n2−1)=m+n2−1=c−1 ,于是,A所有位于橙色方框中的数均小于或等于c-1,位于C的中位数的左边,他们的个数是m2 。
B[b] 在C中的下标位置Cb 最小能排在a所在位置Ca 的后面,所以有Cb≥a+b=m2+(n2)=m+n2=c ,所以A中位于橙色方框中的所有数都位于C的中位数的右边,他们的个数是n2 。
接下来就需要求出Min(n2 ,m2) 。然后剔除A中的前Min(n2 ,m2) 个数,在B中剔除后Min(n2 ,m2) 个数。中位数保持。case3: m为偶数,n为奇数。
看图:
∵A[a]<B[b] ,那么一定有:
A[a] 在C中的下标位置Ca 最大能排在b所在位置Cb 的前面,所以有Ca≤a+b−1=m2+(n+12−1)=m+n+12−1=c−1 ,于是,A所有位于橙色方框中的数均小于或等于c-1,位于C的中位数的左边,他们的个数是m2 。
B[b] 在C中的下标位置Cb 最小能排在a所在位置Ca 的后面,所以有Cb≥a+b=m2+(n+12)=m+n+12=c ,所以A中位于橙色方框中的所有数都位于C的中位数的右边,他们的个数是n+12−1=n−12 。
接下来就需要求出Min(n−12 ,m2) 。然后剔除A中的前Min(n−12 ,m2) 个数,在B中剔除后Min(n−12 ,m2) 个数。中位数保持。
case4: m为奇数,n为偶数。
看图:
∵A[a]<B[b] ,那么一定有:
A[a] 在C中的下标位置Ca 最大能排在b所在位置Cb 的前面,所以有Ca≤a+b−1=m+12+(n2−1)=m+n+12−1=c−1 ,于是,A所有位于橙色方框中的数均小于或等于c-1,位于C的中位数的左边,他们的个数是m+12 。
B[b] 在C中的下标位置Cb 最小能排在a所在位置Ca 的后面,所以有Cb≥a+b=m+12+(n2)=m+n+12=c ,所以A中位于橙色方框中的所有数都位于C的中位数的右边,他们的个数是n2 。
接下来就需要求出Min(n2 ,m+12) 。然后剔除A中的前Min(n2 ,m+12) 个数,在B中剔除后Min(n2 ,m+12) 个数。中位数保持。
< header >
#include<iostream>#include<vector>#include<iterator>using namespace std;
< search Middle >
//注意处理的顺序,这个函数很容易把处理的顺序搞错,实现起来比较耗时间来调试。int search_Midlle_in_2A(vector<int>const* set1, int const &first1, int const& last1, vector<int>const* set2, int const &first2, int const& last2){ int fst1(first1), lst1(last1); int fst2(first2), lst2(last2); int size1(last1 - first1 + 1); int size2(last2 - first2 + 1); //如果一个数值串中的数全部被剔除,那就直接返回另一个数值串的中位数。 //不可能同时出现两个数组大小均为0的情况,所以这里的数组访问是合理的。 if (size1 == 0){ return (*set2)[(fst2 + (size2 + 1) / 2 - 1)]; } if (size2 == 0){ return (*set1)[(fst1 + (size1 + 1) / 2 - 1)]; } //计算中位数的位置【直接对应其在数组中的下标】 //这里的下标计算也是合理的。 int Middle1(fst1 + (size1 + 1) / 2 - 1); int Middle2(fst2 + (size2 + 1) / 2 - 1); //如果两个数组的中位数相等,这个数的就是他们的中位数。 if ((*set1)[Middle1] == (*set2)[Middle2]) return (*set1)[Middle1]; //使得set1的中位数是较小的一个 if ((*set1)[Middle1] > (*set2)[Middle2]){ //交换集合的指向 vector<int>const *temp = set1; set1 = set2; set2 = temp; //同时交换其他相关的值 Middle1 = (first2 + (size2 + 1) / 2 - 1); Middle2 = (first1 + (size1 + 1) / 2 - 1); size1 = (last2 - first2 + 1); size2 = (last1 - first1 + 1); fst1 = first2; lst1 = last2; fst2 = first1; lst2 = last1; } int min(0);//本次将要被剔除的元素个数。 if (size1 % 2 == 1 && size2 % 2 == 1){//两个数组都含有奇数个元素。 if (size1 == 1) {//这是唯一的一种特殊情况,如果不做处理就会陷入无限循环。 if (size2 == 1) return (*set1)[fst1]; return (*set1)[fst1] > (*set2)[Middle2 - 1] ? (*set1)[fst1] : (*set2)[Middle2 - 1]; } min = size1/ 2 ; if (size1 > size2+2) min = size2/2 ; } if (size1 % 2 == 0 && size2 % 2 == 0){//两个数组都含有偶数个元素。 min = size1 / 2; if (size1 > size2) min = size2/2 ; } if (size1 % 2 == 1 && size2 % 2 == 0){//set1含有奇数个元素,set2含有偶数个元素。 min = (size1+1)/ 2; if (size1 > size2 -1) min = size2 /2; } if (size1 % 2 == 0 && size2 % 2 == 1){//set2含有奇数个元素,set1含有偶数个元素。 if (size2 == 1){//这是一种特殊情况,如果不做处理就会陷入无限循环。 return (*set2)[fst2] < (*set1)[Middle1 + 1] ? (*set2)[fst2] : (*set1)[Middle1 + 1]; } min = size1/2; if (size1 > size2-1) min = size2/2; } //根据中位数保持定理,继续递归。 search_Midlle_in_2A(set1, fst1 + min, lst1, set2, fst2, lst2 - min);}int search_Midlle_in_2A(vector<int> * const set1,vector<int>* const set2){ int size1 = (*set1).size(); int size2 = (*set2).size(); return search_Midlle_in_2A(set1,0,size1-1,set2,0,size2-1);}
< main >
int main(){ vector<int> set1, set2; cout << "请输入第一个集合(递增), 按ctrl+z结束输入:" << endl; copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(set1)); cin.clear(); cin.sync(); cout << "请输入第二个集合(递增), 按ctrl+z结束输入:" << endl; copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(set2)); cout<<"中位数是:"<<search_Midlle_in_2A(&set1,&set2)<<endl; cout << endl; system("pause"); return 0;}
- 寻找两个排序数组的中位数
- 寻找两个数组的中位数
- leetcode题目 寻找两个排序数组的中位数
- 两个排序数组的中位数
- 两个排序数组的中位数
- 两个排序数组的中位数
- 两个排序数组的中位数
- 两个排序数组的中位数
- 两个排序数组的中位数
- 两个排序数组的中位数
- 两个排序数组的中位数
- 【leetcode】寻找两个已排序数组的中位数(类似二分)
- leetcode 求两个排序数组的中位数
- 求两个排序数组的中位数
- 找两个排序数组的中位数
- 【算法】【分治】两个排序数组的中位数
- 找出两个排序数组的中位数
- LintCode 两个排序数组的中位数
- Linux多线程与同步
- 磁盘缓存
- bzoj3174【TJOI2013】拯救小矮人
- apache lucene solr 官网历史版本下载地址
- BZOJ3160 万径人踪灭 FFT+manacher
- 寻找两个排序数组的中位数
- iframe 中使用 window.name
- iOS runtime 机制 通过别扩展category给一个类添加属性
- C++ Primer 第三章
- 软件设计模式——工厂方法模式(Factory Method)
- 快速排序
- 竖式问题
- bzoj3175【TJOI2013】攻击装置
- 合并ajax请求