题目要求:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字
看到有同学做了“选取奇数个数的数字”的题目,但是题目为
“一个整型数组里除了一个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字”
可以采用排序的方法求解,让数字成对出现,但是排序的算法最优时间复杂度是 O(nlog2n),也可以采用异或求解,利用异或的方法,可以让相同的两个数字相互异或消除,达到求解目的。
例:a[100] = {7,1,2,3,1,2,3,4,4}
#include "stdio.h"
int number(int a[], int n) {
int i;
int result = 0;
for (i = 0; i<n;i++) {
result ^= a[i];
}
return result;
}
int main(void) {
int a[100] = {7,1,2,3,1,2,3,4,4};
printf("%d\n",number(a, 9));
}
但是如果结果有两个只出现一次的数字时,又该如何求解?
例:a[100] = {7,6,1,2,3,1,2,3,4,4}
结果会出现7和6的位相与后的结果 1,而不是7和6。
做题思路:
按照正常思路最终结果是求出a^b的值,为了求那两个奇数个的数,可以通过a = (a^b) ^ b 和 b = (a^b) ^ a来求解a和b, (a ^ b)已知,剩下的就是通过(a ^ b)想办法求出a和b的数字了。
①:求(a ^ b)
②:利用(a ^ b)求a,b
例中数组{7,6,1,2,3,1,2,3,4,4}求得的(a ^ b)为 7^6,二进制表示为0111和0110,所以(a ^ b)的结果会求得0001,然后我们要通过0001来分析。
首先出现位为1的可能就是位不相等异或出来的,可以将数组分为两个子数组,我们把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其他数字都出现两次。
如:a[100] = {7,6,1,2,3,1,2,3,4,4} 可变成{0111,0110,0001,0010,0011,0001,0010,0011,0100,0100}
分成两个子数组分别为a = {, 000,001,000,001}(通过(a ^ b)= 0001获得所有结尾为的数)和b = {,0010,0010,0100,0100},将子数组内元素相异或,即求得a和b
#include "stdio.h"
//获得(a ^ b)上的第一个位为1的位置
int FindFirstBitls1(int num) {
int indexBit = 0;
while ((num & 1) == 0) {
num = num >> 1;
++ indexBit;
}
return indexBit;
}
//判断数组中的元素是否指定的位为1
_Bool IsBit1(int num, int indexBit) {
num = num >> indexBit;
return (num & 1);
}
void number(int array[], int n, int a, int b) {
int i,j;
int result = 0;
for (i = 0; i<n;i++) {
result ^= array[i];
}
int indexOf1 = FindFirstBitls1(result);
a = b = 0;
for (j = 0; j<n; ++j) {
if(IsBit1(array[j], indexOf1)) //位为1,存入a数组
a ^= array[j];
else //否则,存入b数组
b ^= array[j];
}
printf("%d\n",a);
printf("%d\n",b);
}
int main(void) {
int array[112] = {6,1,2,3,1,2,3,4,4,7};
int a,b;
number(array, 10, a, b);
}