一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
例如:
有数组的元素是:1,2,3,4,5,1,2,3,4,6
只有5和6只出现1次,要找出5和6.
要找到只出现过一次的数字,可以利用异或的性质,(同则零不同则一),所以两个相同的数字进行异或就获得到全零,零异或上一个数结果就等于这个数。,所以先把数组元素都进行异或(异或具有交换律)得到的结果等于数组中那两个数字异或
#include <stdio.h>
void findSingleNumbers(int arr[], int n) {
int xorResult = 0;
for (int i = 0; i < n; i++) {
xorResult ^= arr[i];
}
// 找到异或结果中第一个为1的位数
int rightmostSetBit = xorResult & -xorResult;
int num1 = 0, num2 = 0;
for (int i = 0; i < n; i++) {
if (arr[i] & rightmostSetBit) {
num1 ^= arr[i];
}
else {
num2 ^= arr[i];
}
}
printf("只出现一次的数字是:%d 和 %d\n", num1, num2);
}
int main() {
int arr[] = { 1, 2, 3, 4, 5, 1, 2, 3, 4, 6 };
int n = sizeof(arr) / sizeof(arr[0]);
findSingleNumbers(arr, n);
return 0;
}
,所以这个结果的二进制中的1 就是说明在这位上这两个数是不同的(有分歧的),我们需要找到任意有分歧的一位就可以把二者找出来,接下来就是要找到一位分歧位并记录他是第几位二进制位
就如同代码中的 int rightmostSetBit = xorResult & -xorResult;
首先,
xorResult
是一个整数,我们假设它的二进制表示形式为xxxxxxxx...xxx1xxx...xxx
,其中x
可以是0或1。
-xorResult
是将xorResult
的二进制表示形式取反,并加1。这可以通过以下步骤实现:
- 求
xorResult
的二进制补码(将 0 变为 1,将 1 变为 0)。- 加上1。
例如,如果
xorResult
的二进制表示为10111010
,则-xorResult
的二进制表示为01000110
。按位与(
&
)操作将xorResult
和-xorResult
进行按位运算。这将导致所有位都被清除,除了最右边的设置位。因为在-xorResult
中,只有最右边的设置位和xorResult
相同位置的设置位为1,其他位都为0。因此,通过执行
xorResult & -xorResult
,我们得到的结果是一个整数,它只有最右边的设置位为1,其他位都为0。这将帮助我们识别最右边的设置位在哪个位置。
然后就用每个数组元素与上这个只有在分歧位是一的数,这就把数分为两类了,一个是结果为0,一个结果为1,然后设置两个接受的值赋为零(在此利用0异或为本身的性质)然后相同的数再次异或为零,最后这两个数中剩下的就是我们要的“单身狗”了