要求中位数,关键是要找到第k小的数,命名为findk()。这里我们分为两种情况分析,如果是数组的长度为奇数,只调用一次findk();如果是数组的长度是偶数则调用2次findk()。
Findk()的算法为:
(1)判断A[k/2-1]与B[k/2-1]的大小(也就是取两个数组中前k/2个数),如果数组的长度不足k/2,用A[max-1],B[max-1]来取代,这里使用index表示,index=min(k/2-1,max/2-1),A的index为记作index1,B的index记作index2。
1.1如果A[index1]>B[index2],则说明B[0]~B[index2]的数都不会是第K小的数,所以将这index2+1个数去掉,现在问题转化为剩下的m+n-index2-1个数中第k-index2-1小的数,即m=m,n=n-index2-1,k=k-index2-1,回到步骤(1)
1.2如果A[index1]=B[index2],要分两种情况讨论。如果k为偶数则A[index1]就是我们需要的数,如果k为奇数,则所取的数都是无用的,因为/代表的是取整计算。比如k=5,则我们总共取出来4个数,而且第3、4个是相等,所以这4个数都可以都是可以舍掉的。返回步骤(1)
1.3如果A[index1]<B[index2],如1.1所述,去掉A中前index+1个数,此时m=m-index-1,n=n,k=k-index1-1,回到步骤(1)
至此迭代的主循环已经完成。按照最坏的情况计算,每次去掉k/2个数,直到k=1时,
min(A[0,B[0])即为所求,这样k的变化为k,k/2,k/4…..(事实上这里存在一个k-k/2!=k/2的问题),经过n次迭代之后 ,可得时间复杂度为n=logk。
程序中的几点注意事项:
1. 如果是空向量vc,那么vc.begin()和vc.end()等无意义,会报错!
2.对于vs2010而言并不支持列表初始化如vector<int>nums{1,2,3};对向量初始化要通过push_back()
3..向量的erase操作的参数是迭代器,原先一直以为是下标。同时需特别注意erase之后指向该元素的迭代器将会失效。比如
iter1=nums.begin()+1;
nums.erase(iter1);
cout<<*iter1;
//此时访问将会出错 not dereferencable
4 函数声明时像void fun(vector<int>&num),num是原向量的引用,对原向量进行了地址的传递,对num的操作即为对原向量的操作,如果函数名是void fun(vector<int >num), 则仅仅是值传递对num的操作并不会影响原向量。
5.两个向量可以相互赋值,如vec1=vec,这两个向量的值是相同的,仅仅是赋值,对Vec1的操作并不会影响vec。
int findk(vector<int> nums1, vector<int> nums2,int k)
{
int m=nums1.size(); int n=nums2.size();
int index1,index2;
vector<int>::iterator iter1,iter2;
index1=min(m-1,k/2-1);
index2=min(n-1,k/2-1);
if (nums1.empty()) //如果有一个为空直接返回中位数
return nums2[k-1];
if(nums2.empty())
return nums1[k-1];
if (k==1)
return min(nums1[0],nums2[0]);
iter1=nums1.begin()+index1;
iter2=nums2.begin()+index2;
if (nums1[index1]>nums2[index2])
{
nums2.erase(nums2.begin(),iter2+1);//舍掉前index2 +1个
k=k-index2-1;
}
else if (nums1[index1]<nums2[index2])
{
nums1.erase(nums1.begin(),iter1+1);
k=k-index1-1;
}
else
{
if (k%2)//奇数相等都舍掉
{
nums2.erase(nums2.begin(),iter2+1);
nums1.erase(nums1.begin(),iter1+1);
k=k-index1-index2-2;
}
else //偶数相等返回中位数
return nums1[index1];
}
return findk(nums1,nums2,k);
}
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m,n,temp1,temp2;
double median;
m=nums1.size();
n=nums2.size();
if ((m+n)%2)
{
median=findk(nums1,nums2,(m+n)/2+1);
}
else
{
temp1=findk(nums1,nums2,(m+n)/2);
temp2=findk(nums1,nums2,(m+n)/2+1);
median=(temp1+temp2)*1.0/2;
}
return median;
}
};