问题描述
一个整型数组里面除了两个数字之外,其他的数字都出现了两次。请找出这两个数字来,
时间复杂度为O(N),空间复杂度为O(1)
问题分析
如果要是只有一个数字只出现一次,其他的都出现两次,那么很容易想到,
异或:任何一个数字异或本身,都等于0。(相同为0,相异为1)。
思路:
将该数组分为两个子数组,每个子数组都包括1个只出现1次的数字,
那么分别将这个子数组中的数字异或,就分别得到一个结果。
那么如何将数组分为两个子数组呢
可以将原数组总所有的数字进行异或,最后得到一个结果,结果肯定不为0,即:该结果中的二进制中至少有一位为1,我们在结果数字中找到第一个为1的位置,记为第n位。
根据第n位是否为1,将数字分为两个部分。
实现
//找出第一个为1的位置,
unsigned int FindFirstBit1(int num)
{
int idxBit = 0;
while ((num & 1) == 0 && (idxBit < sizeof(int)* 8))
{
num = num >> 1;
++idxBit;
}
return idxBit;
}
//判断这个数字的第n位是否为1
bool IsBit1(int num, unsigned int idxBit)
{
num = num >> idxBit;
return (num & 1);
}
void FindNumsAppearOnce(int arr[], int len, int *num1, int* num2)
{
if (arr == NULL || len <= 0)
return;
int res = 0;
for (int i = 0; i < len; ++i)
res ^= arr[i];
//找出第一个为1的位置
int idxBit = FindFirstBit1(res);
for (int j = 0; j < len; ++j)
{
if (IsBit1(arr[j], idxBit))
{
*num1 ^= arr[j];
}
else
{
*num2 ^= arr[j];
}
}
}
void TestFindNumsAppearOnce()
{
int arr[] = { 2, 4, 3, 6, 3, 2, 5, 5 };
int num1 = 0, num2 = 0;
FindNumsAppearOnce(arr, 8, &num1, &num2);
}