您的位置:首页 > 其它

一组数字中只有两个数单独出现,其他数成对出现,找出这两个数

2017-04-23 14:03 260 查看

在写过一个数字单独出现后,知道全体异或后成对出现的数字将抵消,这次将得到两个单独出现的数字的结果

得到两个单独出现数字异或的结果后,把两个数字分离出来就可以了,但通过x^y得到其中一个数字需要另一个数字,无法分离,但是我们知道异或为1的位两个数该位必然不同,通过这个比特位把数字分为两组,再分别异或就可以得到这两个数了

void check_num(int *arr, int sz,int *x,int *y)
{
*x = 0;
*y = 0;
int n = 0;
int i = 0;
for (i = 0; i < sz; i++)
{
n ^= arr[i];//得到两个单独出现的数字异或的结果
}
n = n & ((n - 1)^-1);//取出第一个非零比特位
//(n-1)把第一个非零比特位置零,^1按位取反[-1的补码位为全1]保留第一个刚置零的比特位,
//过程见http://blog.csdn.net/mzx1317557721/article/details/70495637
for (i = 0; i < sz; i++)
{
if (arr[i] & n)
*x ^= arr[i];
else
*y ^= arr[i];
}
}


arr为数组首元素地址

sz为数组元素个数

x,y为接收两个单独出现数字的变量

当然也可以暴力求解,如果想不出好方法就只能遍历两次了

网上还有一种通用方法,当数组内的数字都比较小的时候可以用

建立一个大于数组内最大数字的数组,初始化为0,当某个数字出现一次的时候,对应下标数字加一,最后某个数字出现几次看下标就好了

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

//调用函数
void first_num(int * str)
{
assert(str);        //断言,判断传进的数组指针是否有效,用以抛出异常。
int asc[10] = { 0 };    //创建一个十个元素的数组,
//因为原数组元素的大小都只为0~9的元素,可根据需要自行设定大小。
int i = 0;
for (i = 0; i<10 ; i++)
{
asc[str[i]]++;    //将原数组的元素作为新建数组的下标,并自增。
//如果原数组有相同元素,说明在新建数组对应的位置处的值会不断加1。
}
printf("出现一次的两数为:\n");
for (i = 0; i<10; i++)
{
if (asc[str[i]] == 1)    //输出条件,只要新建数组的值仍为1,说明原数组中该元素只有一个。
{
printf("%d ", str[i]);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐