算法二十天
第七天
寻找两个正序数组的中位数
给定两个数组求合并后其中位数。要求时间复杂度为log(m+n);
/例子 cin>> nums1=[1,3],nums2=[2]
cout<< 2.00000
解释:合并数组找出中位数;/
这道题就体现了基础的重要性,在写二分归并排序时写过合并这一函数,看到题目立马就反应过来:
#include<bits/stdc++.h>
using namespace std;
vector<int> HeBing(vector<int> &a,vector<int> &b)
{
vector<int> temp;
int i=0,j=0;
while(i<a.size()&&j<b.size())
{
if(a[i]>=b[j])
{
temp.push_back(b[j]);
j++;
}
else
{
temp.push_back(a[i]);
i++;
}
}
while(i<a.size())
{
temp.push_back(a[i]);
i++;
}
while(j<b.size())
{
temp.push_back(b[j]);
j++;
}
return temp;
}
double Mid(vector<int> &temp)
{
if(1&temp.size())//判断奇数还是偶数个
return temp[temp.size()/2];
else
return (double)(temp[temp.size()/2]+temp[temp.size()/2-1])/2;
}
int main()
{
vector<int> a={
1,2};
vector<int> b={
3,4};
vector<int> temp=HeBing(a,b);
printf("%0.5f",Mid(temp));
}
并不符合题目要求的时间复杂度,明天再写
看到log就想到了用二分法,这个如何二分呢?首先中位数是中间的那个数,所以我们只要找出一个数是第k个数使用二分法将问题一分为二:
即求数组a和b所有元素中的第5小的数
那么当a[k/2-1]<b[k/2-1]能够排除的不是第k小的数是a[k/2-1]及之前,因为a[k/2-1]及之前的数最多是第k/2+k/2-1大,(当b[k/2-1]及之前的数都小于a[k/2-1]),这时候排除了两个元素,那现在需要求得是剩下元素中第k-k/2大的数
直到k==1即无法在分结束,对于偶数再求一个第k+1大的数即可
#include<bits/stdc++.h>
using namespace std;
int f(vector<int> &nums1,vector<int> &nums2,int k)
{
int m=nums1.size();
int n =nums2.size();
int index1=0,index2=0;
while(true)
{
if(index1==m)
return nums2[index2+k-1];
if(index2==n)
return nums1[index1+k-1];
if(k==1)
return min(nums1[index1],nums2[index2]);
int i=min(index1+k/2-1,m-1);
int j=min(index2+k/2-1,n-1);
int pivot1=nums1[i];
int pivot2=nums2[j];
if(pivot1<=pivot2)
{
k-=i-index1+1;
index1=i+1;
}
if(pivot1>pivot2)
{
k-=j-index2+1;
index2=j+1;
}
}
}
double m(vector<int> &nums1,vector<int> &nums2)
{
int length=nums1.size()+nums2.size();
if(length%2==1)//判断奇偶
return f(nums1,nums2,(length+1)/2);
else
return (f(nums1,nums2,length/2)+f(nums1,nums2,length/2+1))/2.0;
}
int main()
{
vector<int> a={
1,2};
vector<int> b={
3,4};
double temp=m(a,b);
printf("%0.5f",temp);
}
时间复杂度O(log(m+n));