转自:https://blog.youkuaiyun.com/qq_31217423/article/details/52974663
一个无序数组里有若干个正整数,范围从1到100,其中98个整数都出现了偶数次,只有两个整数出现了奇数次(比如1,1,2,2,3,4,5,5),如何找到这个出现奇数次的整数?
解法:
遍历整个数组,依次做异或运算。由于数组存在两个出现奇数次的整数,所以最终异或的结果,等同于这两个整数的异或结果。这个结果中,至少会有一个二进制位是1(如果都是0,说明两个数相等,和题目不符)。
举个例子,如果最终异或的结果是5,转换成二进制是00000101。此时我们可以选择任意一个是1的二进制位来分析,比如末位。把两个奇数次出现的整数命名为A和B,如果末位是1,说明A和B转为二进制的末位不同,必定其中一个整数的末位是1,另一个整数的末位是0。
根据这个结论,我们可以把原数组按照二进制的末位不同,分成两部分,一部分的末位是1,一部分的末位是0。由于A和B的末位不同,所以A在其中一部分,B在其中一部分,绝不会出现A和B在同一部分,另一部分没有的情况。
这样一来就简单了,我们的问题又回归到了上一题的情况,按照原先的异或解法,从每一部分中找出唯一的奇数次整数即可。
假设数组长度是N,那么该解法的时间复杂度是O(N)。把数组分成两部分,并不需要借助额外存储空间,完全可以在按二进制位分组的同时来做异或运算,所以空间复杂度仍然是O(1)。
-
#include<stdio.h>
-
void main()
-
{
-
int arr[
10] = {
1,
1,
2,
2,
3,
5,
5,
5,
6,
6};
-
int i, xor = arr[
0], bit_num =
0, value =
0, a =
0, b =
0;
-
for(i =
1; i <
10; i++)
-
{
-
xor = xor ^arr[i];
-
}
-
while(value !=
1)
-
{
-
value = (xor>>bit_num) &
1;
-
bit_num++;
-
}
-
for(i =
0; i <
10; i++)
-
{
-
if((arr[i]>>(bit_num
-1)) &
1)
-
{
-
a = a ^ arr[i];
-
}
-
else
-
{
-
b = b ^ arr[i];
-
}
-
}
-
printf(
"the number is %d and %d.",a,b);
-
}