1、一个数字出现一次,其他数字出现两次
两个相同的数异或为0,所以将数组里的所有数依次异或,得到的结果就是只出现一次的数。
#include <iostream>
using namespace std;
int main()
{
int a[]={3,6,2,3,2,5,5};
int num=0;
for(int i=0;i<7;i++)
{
num^=a[i];
}
cout<<num<<endl;
return 0;
}
2、一个数字出现一次,其他数字出现N次
通过观察法,发现如果数字出现了n次,那么每一bit位之和可以被n整除。
#include <iostream>
#include <string>
using namespace std;
int FindNumber(int a[], int n, int m)
{
int bits[32];
int i, j;
// 累加数组中所有数字的二进制位
memset(bits, 0, 32 * sizeof(int));
for (i = 0; i < n; i++)
for (j = 0; j < 32; j++)
bits[j] += ((a[i] >> j) & 1);
// 如果某位上的结果不能被整除,则肯定目标数字在这一位上为
int result = 0;
for (j = 0; j < 32; j++)
if (bits[j] % m != 0)
result += (1 << j);
return result;
}
int main()
{
int a[] = {2, 3, 1, 2, 3, 4, 1, 2, 3, 1};
//3代表其他数字出现3次
cout<<FindNumber(a, 10, 3)<<endl;
return 0;
}
3、两个数字出现一次,其他数字出现两次
和1的原理差不多,先是分别异或,得到结果,肯定不为0。找到结果1所在的位置x,将原数组分为两部分,第一部分是x为1的数的集合,第二部分是x为0的数的集合。然后分别对这两个数组异或,得到这两个出现一次的数。
#include <iostream>
#include <string>
using namespace std;
unsigned int FindFirstBitIs1(int num)
{
int indexBit=0;
while(((num&1)==0)&&(indexBit<8*sizeof(int)))
{
num=num>>1;
++indexBit;
}
return indexBit;
}
bool IsBit1(int num,unsigned int indexBit)
{
num=num>>indexBit;
return (num&1);
}
void FindNumsAppearance(int data[],int length,int *num1,int *num2)
{
if (data==NULL||length<2)
{
return;
}
int resultExclusiveOR=0;
for (int i=0;i<length;i++)
{
resultExclusiveOR^=data[i];
}
unsigned int indexof1=FindFirstBitIs1(resultExclusiveOR);
*num1=*num2=0;
for (int j=0;j<length;j++)
{
if (IsBit1(data[j],indexof1))
{
*num1^=data[j];
}
else
{
*num2^=data[j];
}
}
}
int main()
{
int a[]={4,3,6,3,2,5,5};
int temp1,temp2;
FindNumsAppearance(a,7,&temp1,&temp2);
cout<<temp1<<"\t"<<temp2<<endl;
return 0;
}
参考: