《编程珠玑》1.5节:快速找出故障机器
主要是能够在一组数组中找出丢失的数。
1、在数组A中,除了一个数只出现一次外,其他数都出现两次。用异或来解,最后得到的数就是丢失的数。
#include<iostream>
using namespace std;
int findLost(int A[],int N)
{
int result=0;
for(int i=0;i<N;i++)
result^=A[i];
return result;
}
int main()
{
const int N=9;
int A[N]={1,2,3,4,1,2,3,4,8};
cout<<findLost(A,N)<<endl;
system("pause");
return 0;
}
2、在数组A中,除了两个数只出现一次外,其他数都出现两次。用两次异或来解。第一次异或找出的是两个丢失的数的异或,此时根据异或结果,可以找出两个数的不同的位,比如第bit位,那么进行第二次异或时,bit位为1的值和num1进行异或,bit位为0的值和num2进行异或,最后可以得到两个数。
#include<iostream>
#include<algorithm>
using namespace std;
pair<int,int> findLostTow(int A[],int N)
{
int num1=0,num2=0;
for(int i=0;i<N;i++)
num1^=A[i];
int bit=0;
for(int i=0;i<32;i++)
{
if(num1 & (1<<i))
{
bit=i;
break;
}
}
num1=0;
for(int i=0;i<N;i++)
{
if(A[i]&(1<<bit)==1)
num1^=A[i];
else
num2^=A[i];
}
return pair<int,int>(num1,num2);
}
int main()
{
const int N=10;
int A[N]={1,2,3,4,1,2,3,4,8,7};
pair<int,int> p=findLostTow(A,N);
cout<<p.first<<" "<<p.second<<endl;
system("pause");
return 0;
}
3、如果数组中丢失数之前已经知道数组和,即这些先验是已知的,那么就可以用其和,平方和,或者乘积等对丢失数据进行计算,然后列方程求解。例如求数组中丢失的两个数时,用二元二次方程求解:
#include<iostream>
#include<algorithm>
using namespace std;
pair<int,int> findLostTow(int A[],int N,int sum,int powSum)
{
int s=0,pows=0;
for(int i=0;i<N;i++)
{
s+=A[i];
pows+=A[i]*A[i];
}
int num1=0,num2=0;
int add=sum-s,minus=int(sqrt(double(2*powSum-2*pows-sum*sum-s*s+2*s*sum)));
return pair<int,int>((add+minus)>>1,(add-minus)>>1);
}
int main()
{
const int N=10;
int A[N]={1,2,3,4,1,2,3,4,8,7};
pair<int,int> p=findLostTow(A,N,50,286);
cout<<p.first<<" "<<p.second<<endl;
system("pause");
return 0;
}
4、如果要求的未知数增多,只需要增加方程即可,但是随着未知数个数增多,复杂度也会上升。