数组中数字出现的次数
问题描述
一个整型数组
nums
里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例
输入:nums = [4,1,4,6] 输出:[1,6] 或 [6,1] 输入:nums = [1,2,10,4,1,4,3,3] 输出:[2,10] 或 [10,2]
解题思路
用异或方法进行解决,我们都知道要是有一个数只出现一次,根据异或的原理,那么我们将所有数全部异或,则结果就为出现一次的数字。这个问题是有两个数出现了一次,那么首先的思路就是将这两个数分开,分成两组。使得
-
两个只出现一次的数字在不同的组中;
-
相同的数字会被分到相同的组中。
如何将两个数组分开呢?
首先我们先将所有数进行异或,这个异或结果即是两个不同的数异或的结果,然后找出其中任意一位1,然后进行分组。
- 首先,两个相同的数字的对应位都是相同的,所以一个被分到了某一组,另一个必然被分到这一组。
- 其次,因为取的数为两个数异或结果为1的那一位,代表在这个位上,两个数是不同的(分别为1、0或0、1),所以一个数被分到了某一组,另一个数一定会被分到其他的组。
分好组后,将每组的数字分别异或得到的结果就是只出现一次的那个数。
代码实现:
void singleNumbers(int* nums, int numsSize)
{
int sum = 0;
//先求出两个不同数的异或结果
for (int i = 0; i < numsSize; i++)
{
sum ^= nums[i];
}
int x = 1; //找出异或结果中任意一位1
while ((x & sum) == 0)
{
x <<= 1;
}
int* ret = (int*)malloc(sizeof(int) * 2);
ret[0] = ret[1] = 0; //进行分组,将不同的数分在不同的2组
for (int j = 0; j < numsSize; j++)
{
if (x & nums[j])
{
ret[0] ^= nums[j];
}
else
{
ret[1] ^= nums[j];
}
}
printf("%d,%d\n", ret[0], ret[1]);
}
结果如下: