✨✨欢迎大家来到Celia的博客✨✨
🎉🎉创作不易,请点赞关注,多多支持哦🎉🎉
所属专栏:【每日刷题】C语言
个人主页:Celia's blog~
题目
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
例如:
有数组的元素是:1,2,3,4,5,1,2,3,4,6
只有5和6只出现1次,要找出5和6.
解题思路
这道题可以巧用异或的方式来解答,在此之前,让我们先来了解异或操作符的运算法则:
异或(^):用二进制形式对比两个变量的每一位,如果不同则为1,如果相同则为0。
我们可以得到以下重要推论:
- n^n=0
- 0^n=n
了解了异或操作符的运算法则后,我们可以在此基础上列出此题的大致思路:
先简化一下问题:
如果有一个数组其中只有一个元素单独出现,其他都是成对出现,找出单独出现的元素。
int arr[]={1,2,3,4,5,1,2,3,4};
我们可以遍历这个数组的每一个元素进行异或操作:
int sz = sizeof(arr)/sizeof(int); int i, ret = 0;//ret初始化为0,这样能保证ret^arr[0]的值为数组第一个元素 for(i = 0; i < sz; i++) { ret ^= arr[i]; }
异或运算符是符合交换律的,遍历一次后相当于上图的操作,最后剩下的就是只出现一次的数字了。
这个简化后的版本和本题的区别是:简化的版本只有一个元素单独出现,本题有两个元素单独出现。我们只需要把本题中的数组分为两组,每一组只有一个元素单独出现,每一组都利用上文的方法,就可以解决此题。那么问题又来了,该按何种方法进行分组呢?
以下是大致思路:
- 既然有两个数单独出现,那么单独出现的这两个数一定是不同的两个数。
- 既然是不同的两个数,在二进制位上一定有一个或者多个位数是不同的。
- 我们可以记录这两个数到底是在第几位二进制数位上是不同的,并且找出其中一个的位置。
- 按照这个位置为0或者为1对数组中所有的数进行分组。
有了解题思路,那就先进行第一步:找出这两个数在二进制位上哪个位置是不同的。我们仍然可以遍历数组的每一个元素进行异或操作,这样一来,成对出现的数字互相异或的结果为0,最后剩下的就是两个不同数字异或的结果,这个结果在二进制位上 ‘1’ 的位置就是我们要找的位置。
int arr[]={1,2,3,4,5,1,2,3,4,6};
//5和6只出现一次,其他数字成对出现
int sz = sizeof(arr)/sizeof(int);
int i, ret = 0;
for(i = 0; i < sz; i++)
{
ret ^= arr[i];//最后是5^6的结果
}
接下来我们要确定这两个数在二进制的第几位是不同的,确定其中一个位置即可。
for (i = 0; i < 32; i++)//最多有32位
{
if (((ret >> i) & 1) == 1)//右移检查每一个二进制位,与1按位与如果等于1,说明这个二进制位为1
{
//ret二进制位上的‘1’即为两个数二进制位上的不同之处
flag++;//二进制位上的数只有0和1两种可能,找到一个不同之处即可,凭此即可区分两个数。
break;
}
}
//以下代码为自定义函数中的代码片段
for (i = 0; i < sz; i++)
{
if (((arr[i] >> flag) & 1) == 1)//将数组中的每一个元素右移flag位进行判断
{
*p1 ^= arr[i];//p1最终的结果将保存第一个单独出现的数,p1初值为0
}
else
*p2 ^= arr[i];//p2最终的结果将保存第二个单独出现的数,p2初值为0
}
这样就变相的将数组中的元素分为两组分别进行遍历异或操作,最终得出结果。
完整代码
#include <stdio.h>
void find_dog2(int arr[10], int* p1, int* p2,int sz)
{
int i, flag = 0, n = 0;
for (i = 0; i < sz; i++)
{
n ^= arr[i];
}
for (i = 0; i < 32; i++)
{
if (((n >> i) & 1) == 1)
{
flag++;
break;
}
}
for (i = 0; i < sz; i++)
{
if (((arr[i] >> flag) & 1) == 1)
{
*p1 ^= arr[i];
}
else
*p2 ^= arr[i];
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,1,2,3,4,6 };
int p1 = 0, p2 = 0;
int sz = sizeof(arr) / sizeof(int);
find_dog2(arr, &p1, &p2,sz);
printf("第一个数字是:%d,第二个数字是:%d", p2, p1);
return 0;
}
以上就是本题题解的全部内容啦~
如果觉得有所收获的话,记得点赞关注支持一下~