题目来源:微信公众平台九章算法。因为九章算法仅仅给出了算法,并没有给出源码,这里笔者依据自己的能力给出了源码。当然可能会有非常多不足。希望大家不吝不吝赐教。 -——— 肖然
题目描写叙述:
有2n+1个数。当中2n个数两两成对,1个数落单,找出这个数。要求O(n)的时间复杂度,O(1)的空间复杂度。进阶问题:假设有2n+2个数,当中有2个数落单,该怎么办?
题目分析:
异或的性质,对于随意a,a^a=0; a^0=a;依据这两条性质能够写出下列代码。
初阶:将2n+1个数异或起来,同样的数会抵消,异或的答案就是要找的数。
进阶:如果两个不同的数是a和b。而且a!=b,将2n+2个数异或起来就会得到c=a xor b,而且c不等于0。
因此在c的二进制位中找到一个为1的位,可判断在这位上a和b分别为0和1。因此将2n+2个数分为该位位0的组和该位为1的组,两组中各自会包括2n’+1个数和2n’’+1个数,用初阶的算法就可以解决。
源码:
/**
*九章算法面试题一、落单的数
*异或的简单应用
*异或的性质: a^a=0; a^0=a;
*/
#include<iostream>
#include<cstdio>
using namespace std;
int a[10000],b[10000];
int ans,ans0,ans1;
int LuoDan1(int n,int *a){//初阶问题,给出2*n+1个数,仅仅有一个是单个的,求这个数
ans=0;
for(int i=0;i<2*n+1;i++){
ans^=a[i];
}
return ans;
}
int Judge(int n,int k){//推断第k位(从右到左)是否为1
int i=1;
while(i++<k-1) n>>=1;//向左移位k-1位
if(n>>1==1) return 1;//第k位是1,返回1
else return 0;
}
int LuoDan2(int n,int *a){//初阶问题,给出2*n+2个数,仅仅有两个是单个的,求这两个数
ans=0;
for(int i=0;i<2*n+2;i++){
ans^=a[i];
}
int k=1;
//cout<<ans<<endl;
while(ans>0){//找到最低位的1
if((ans&1)==1) break;
++k;
ans>>=1;
}
ans0=ans1=0;
for(int i=0;i<2*n+2;i++){
if(Judge(a[i],k)){//第k位为1
ans1^=a[i];
}
else ans0^=a[i];
}
//cout<<ans0<<" "<<ans1<<endl;
return ans;
}
int main()
{
int n;
while(cin>>n){
int ans=0;
for(int i=0;i<2*n+1;i++){
cin>>a[i];
//ans^=a[i];
}
cout<<LuoDan1(n,a)<<endl;
for(int i=0;i<2*n+2;i++){
cin>>b[i];
}
//cout<<ans<<endl;
LuoDan2(n,b);
cout<<ans0<<" "<<ans1<<endl;
}
return 0;
}