您的位置:首页 > 编程语言 > C语言/C++

C语言实现:一个数组中只有两个数字只出现一次, 其他所有数字都出现了两次。 找出这两个数字

2018-12-20 15:54 489 查看

【思路】
1.先从数组遍历异或的结果开始
(1)两个相同的数异或的结果是0;
(2)所有不为0的数和0异或的结果是本身。

综上两点,一个整型数组中,若只有两个数字只出现一次,其他数字都出现了两次,那么把数组中的所有遍历异或一遍的结果就是只出现一次的两个数字相异或的结果。

不妨先定义一个上述的数组。

int arr[] = { 1, 2, 3, 4, 1, 2, 3, 4, 5, 6 };

可以看到,只有5、6两个数只出现了一次,其他数都出现了两次,那么根据上述分析,把该数组中所有的元素都遍历异或一遍所得的结果就是5和6相异或的结果。

2.把数组中所有的元素分个组
为了方便分析,先把数组中所有元素的二进制表示写出来:

1:> 0001
2:> 0010
3:> 0011
4:> 0100
5:> 0101
6:> 0110

5和6相异或的结果: 0011

可以看到5和6相异或的结果为0011。我们都知道,两个数相异或的结果中的“1”表示这两个数在该位上不同,就像5(0101)和6(0110)的第一和第二个二进制位不同。

接下来,我们就每个数的第一个二进制位进行分类,这样分类的好处是可以天然把该数组中两个只出现一次的数分开,可以分成两种情况:

  1. 第一个二进制位为0
    2(0010)、2(0010)、4(0100)、4(0100)、6(0110)
  2. 第一个二进制位为1
    1(0001)、 1(0001)、3(0011)、3(0011)、5(0101)

在C语言里,我们只要使用以下代码即可对每个元素就第一个二进制位进行分类

for (i = 0; i < 32; i++)//先求出两个只出现一次的数第一次出现的不同位,如5和6的第一个不同二进制位就是第一个二进制位
{
if (xor_result >> i)
{
dif_bit = i;//把第一次出现的不同二进制位放到整型变量dif_bit中
break;
}
}

if ((arr[i] >> dif_bit)&1)//分类现场
*************
else
*************

3.接下来,我们再使用《当一个整型数组中只有1个数字出现一次,其他数字出现两次》的思想就上述分类分别求解即可得到两个只出现一次的数字。附上链接:https://mp.csdn.net/mdeditor/85061826# 步骤二中的代码块中的“分类现场”就变成了:

for (i = 0; i < size; i++)
{
if ((arr[i] >> dif_bit)&1)
*n1 ^= arr[i];
else
*n2 ^= arr[i];
}
2ce09

分析结束。

【完整参考代码】

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

void find_num(int arr[], int size, int* n1, int* n2)
{
int i = 0;//循环变量
int xor_result = 0;//用来存放数组遍历异或后的结果
int dif_bit = 0;//用来存放两个只出现一次的数的第一个不同的二进制位

for (i = 0; i < size; i++)
{
xor_result ^= arr[i];
}

for (i = 0; i < 32; i++)
{
if (xor_result >> i)
{
dif_bit = i;
break;
}
}

for (i = 0; i < size; i++)
{
if ((arr[i] >> dif_bit)&1)
*n1 ^= arr[i];
else
*n2 ^= arr[i];
}
}

int main()
{
int num1 = 0;//用来存放第一个只出现一次的数
int num2 = 0;//用来存放第二个只出现一次的数
int arr[] = { 1, 2, 3, 4, 1, 2, 3, 4, 5, 6 };int size = sizeof(arr) / sizeof(arr[0]);//求得数组元素个数

find_num(arr, size, &num1, &num2);//调用实现功能子函数

printf("%d %d\n", num1, num2);
system("pause");
return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐