目录
题目:
函数实现思路
分离两个待查找的数
定位二进制为1的位数
全部代码实现
示例:
int arr[] = { 1,1,2,2,3,3,4,5,5,6,7,7,8,8,9,9 };
题目:
在数据成对出现的数组中又两个数值只出现了一次,将这两个数值找出来。
思路
如上面的示例,我们需要将4,6这两个只出现一次的数值找到。明显过程较为复杂,我们采用函数包装。
函数设计
我们需要清楚函数的参数,返回类型是什么?
需要处理的是一个数组,采用指针/数组传参,传数组的元素个数;我们需要返回两个数,所以需要返回一个数组,即一个地址,采用整形指针类型。
int* singleNumber(int* arr, int numsSize)
函数实现思路
异或解法:我们知道,使用异或解决只出现一个一次出现的数时,是十分简便的,所以只要将找两个出现一次的数值,转化为找一个出现一次的数值就好解决了。由此可以想到,需要将数据分为两个部分,两个出现一次的数值分别发布在两边,就转化为了求解两个找出现一次的数值的问题了。
分离两个待查找的数
如何分离呢?
我们需要找到这两个数的不同之处,使用异或可以将这两个数区分开来。
那么我们就可以根据这一特性将其分开,我们选取异或(^)后的二进制序列任意一位为1的位数。只要数组中元素对应的这二进制位为1的数值就分到一组,为0的分到另外一组。这里可以分析一下,最后分到两组的元素是怎么样的呢?
(有一个出现一次的数值,其余的都是成对出现的)
为什么是成对出现的呢?
刚刚提到有一位二进制位数相同的进入同一组,那么数值相同二进制序列也就相同,也就会进入同一组,只有两个只出现一次的数值才会被分开分别进入两组。
定位二进制为1的位数
首先定位一个二进制位为1的位数m
int x = 0; int i = 0; for (i = 0; i < numsSize; i++) { x ^= arr[i];//异或 } int m = 0; //定位x二进制序列为1的位数 for (i = 0; i < 32; i++) { if ((x >> i & 1) == 1) { m = i; break; } }
再将其分开
//将出现一次的两个数分开 int x1 = 0; int x2 = 0; for (i = 0; i < numsSize; i++) { if ((arr[i] >> m & 1) == 1) { x1 ^= arr[i];//只有一个数值出现一次其余成对出现的全部被异或完了 } else { x2 ^= arr[i];//只有一个数值出现一次其余成对出现的全部被异或完了 } }
最后返回值就可以了
int* a = (int*)malloc(sizeof(int)*2); a[0] = x1; a[1] = x2; return a;
全部代码实现
#include#include int* singleNumber(int* arr, int numsSize) { int x = 0; int i = 0; for (i = 0; i < numsSize; i++) { x ^= arr[i];//异或 } int m = 0; //定位x二进制序列为1的位数 for (i = 0; i < 32; i++) { if ((x >> i & 1) == 1) { m = i; break; } } //将出现一次的两个数分开 int x1 = 0; int x2 = 0; for (i = 0; i < numsSize; i++) { if ((arr[i] >> m & 1) == 1) { x1 ^= arr[i]; } else { x2 ^= arr[i]; } } int* a = (int*)malloc(sizeof(int)*2); a[0] = x1; a[1] = x2; return a; } int main() { int arr[] = { 1,1,2,2,3,3,4,5,5,6,7,7,8,8,9,9 }; int len = sizeof(arr) / sizeof(int); int i = 0; int* pa = singleNumber(arr, len); for (i = 0; i < 2; i++) { printf("%d ",pa[i]); } free(pa); pa = NULL; return 0; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)