假设我们有n个直径各不相同的螺钉以及n个相应的螺母。我们一次只能比较一对螺钉和螺母,来判断螺母是大于螺钉、小于螺钉还是正好适合螺钉。然而,我们不能拿两个螺母做比较,也不能拿两个螺钉做比较。我们的问题是要找到每一对匹配的螺钉和螺母。为该问题设计一个算法,它的平均效率必须属于集合O(nlogn)。
- 解法:类似于快速排序的思想,第一次选出一枚螺钉与所有螺帽比较,并将比此螺钉大的螺帽放到左侧,比此螺钉小的螺帽放到右侧,同时也选出了与之正好对应的螺帽。用与之正好对应的螺帽把螺钉分为比此螺帽大的,和比此螺帽小的。重复此过程则螺帽与螺钉实现一一对应。时间复杂度为O(n*logn),空间复杂度为O(n)。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n;
void match(int ld[],int lm[],int tm[],int l,int r)
{
if(r>l)
{
//---------用螺钉处理螺帽数组---------
int mid=ld[(l+r)/2];
int l1=l,r1=r;
for(int i=l;i<=r;++i)
{
if(lm[i]<mid) //小于当前螺钉的螺帽放在左侧。
{
tm[l1]=lm[i];
++l1;
}
if(lm[i]>mid) //大于当前螺钉的螺帽放在右侧。
{
tm[r1]=lm[i];
--r1;
}
}
for(int i=l1;i<=r1;i++) tm[i]=mid; //把正好等于当前螺钉的螺帽放在中间
for(int i=l;i<=r;++i) //把分开后的数组赋值回螺帽数组
{
lm[i]=tm[i];
}
//-----------用螺帽处理螺钉数组----------
int mid1=mid;
int l2=l,r2=r;
for(int i=l;i<=r;++i)
{
if(ld[i]<mid1) //小于当前螺帽的螺钉放在左侧。
{
tm[l2]=ld[i];
++l2;
}
if(ld[i]>mid) //大于当前螺帽的螺钉放在右侧。
{
tm[r1]=ld[i];
--r2;
}
}
for(int i=l2;i<=r2;i++) tm[i]=mid1; //把正好等于当前螺帽的螺钉放在中间
for(int i=l;i<=r;++i) //把分开后的数组赋值回螺钉数组
{
ld[i]=tm[i];
}
match(ld,lm,tm,l,l1-1); //往左侧递归
match(ld,lm,tm,r1+1,r); //往右侧递归
}
else return;
}
int main()
{
cin>>n;
int *ld=new int[n+5]; //螺钉数组
int *lm=new int[n+5]; //螺帽数组
int *tem=new int[n+5]; //临时数组
for(int i=0;i<n;i++) cin>>ld[i];
for(int i=0;i<n;i++) cin>>lm[i];
match(ld,lm,tem,0,n-1);
cout<<"匹配后相当于两个数组排序"<<endl;
cout<<"螺钉数组:";
for(int i=0;i<n;++i) cout<<ld[i]<<" ";
cout<<endl;
cout<<"螺帽数组:";
for(int i=0;i<n;++i) cout<<lm[i]<<" ";
cout<<endl;
delete [] ld;
delete [] lm;
delete [] tem;
return 0;
}