原题描述:
一个数组中有一个/两个/三个数字只出现一次,其他数字都出现了偶数次。请找出一个/两个/三个只出现一次的数字?
具体实现如下:(三个出现一次的数字,有些乱,待优化)三种,均已测试通过。
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
// find the three different number in the int array where the other number is exit double
//1.找出数组中的只出现一次的一个数字
//####数组中所有数据异或后得到的值即为所求。(相同值异或为零)
//2.找出数组中的只出现一次的两个数字
//####只要能想办法将这两个数字放在两个数组中,而这两个数组由原数组分出,并且每一个数组除了这个数字外都是成对出现的(即和原数组组成相似)
//####所有数字异或后,按照所得值的二进制数中其中一位为1的位为标志,将数组分成两组,然后按1方法,找出两组中的数字。
//3.找出数组中的只出现一次的三个数字
//####这个要借助到1和2的方法,首先要想办法将三个数字分在两个数组中,而分的标准和2有些相似,也是以某一位是否为1为标志
//####但是有一种情况是,三个数的某一位全为1,这是三个数还是会分到同一数组中,没有达到将他们分在两个数组的目的,所以要找可以将他们分在两个数组的标志位。
//####我是通过判断查找的,当他们又被分到同一组时,则将找到的这个标志位置0,同时查找下一个是1的标志位,然后再分,知道找到能将他们分到不同组的标志位,
//####(这个标志位是肯定存在的,因为他们三个数字各不相同)
//####三个位异或为1的情况只有一下几种:
// 一:0 0 0 0 1 1 1 1
// 二:0 0 1 1 0 0 1 1
// 三:0 1 0 1 0 1 0 1
//异或:0 1 1 0 1 0 0 1
void FindOneNum(int array[],int length,int &num)
{
if(length < 2)
return ;
for(int i = 0; i<length ;i++)
{
num ^= array[i];
}
}
int FindFirstBitIs1(int num);
bool IsBitIs1(int num, int n);
void FindTwoNum(int array[],int length, int &num1,int &num2)
{
if(length < 2)
return ;
int num = 0;
for(int i = 0; i<length ;i++)
{
num ^= array[i];
}
unsigned int n = FindFirstBitIs1(num);
num1 = num2 = 0;
for(int j= 0; j<length; j++)
{
if(IsBitIs1(array[j],n))
{
num1 ^= array[j];
}
else
{
num2 ^= array[j];
}
}
}
void FindThreeNum(int array[],int length, int &num1, int &num2, int &num3)
{
if(length < 2)
return ;
int num = 0;
for(int i = 0; i<length ;i++)
{
num ^= array[i];
}
unsigned int n = FindFirstBitIs1(num);
int n1 = 0, n2=0;
int number1 = 0, number2 = 0;
//申请两个数组,存放分开的元素
int *array1 = new int[length];
int *array2 = new int[length];
while(n<32)
{
int k = 0,t=0;//实现分开的数组的计数
for(int j= 0; j<length; j++)
{
if(IsBitIs1(array[j],n))
{
array1[k++] = array[j];
number1 ^= array[j];
n1++;
}
else
{
array2[t++] = array[j];
number2 ^= array[j];
n2++;
}
}
//三个数在该位上都为1,则三个数被分到同一个组中,当三个没有被分到同一个组中的时候。
if((number1 != 0)&&(number2 != 0))
{
if(n1%2==0)
{
FindTwoNum(array1,n1,num1,num2);
num3 = number2;
}
else
{
FindTwoNum(array2,n2,num1,num2);
num3 = number1;
}
break;
}
//可能三个数的这个这以为上都为1,则判断下一个异或为1的位,知道找到,三个数中所判断位只有一个的是1,另外两个的是0.
//肯定能找到这样的一位,因为,三个数不可能完全相同。
else
{
num = num ^ (1<<n);
n = FindFirstBitIs1(num);
continue;
}
}
delete[] array1;
delete[] array2;
}
int FindFirstBitIs1(int num)
{
int n = 0;
while(((num&1) == 0)&&(n < 32 ))
{
num = num >> 1;
n++;
}
return n;
}
bool IsBitIs1(int num, int n)
{
num = num >> n;
return (num & 1);
}
int main()
{
int array[]={1,1,2,2,3,3,3,5,5,6,7,7,10,8,8,9,9};
int length = sizeof(array)/sizeof(int);
//int num = 0;
//FindOneNum(array,length,num);
//printf("%d",num);
int num1= 0 ;
int num2 = 0;
//FindTwoNum(array, length, num1, num2);
//printf("%d %d",num1,num2);
int num3=0;
FindThreeNum(array,length,num1,num2,num3);
printf("%d %d %d",num1,num2,num3);
return 0;
}