位操作(应该是异或^),目前已知可解决以下问题:
- 数组中,一个元素只出现一次(奇数次),其他出现偶数次;
- 数组中,两个元素只出现一次(奇数次),其他出现偶数次;
解决方法详见这两篇博客:
http://blog.csdn.net/morewindows/article/details/7354571
http://blog.csdn.net/morewindows/article/details/8214003
这里将要介绍的是这样一个问题:
数组A中,除了某一个数字x之外,其他数字都出现了三次,而x出现了一次。请给出最快的方法找到x。
解决思路:
如果数组中没有x,那么数组中所有的数字都出现了3次,在二进制上,每位上1的个数肯定也能被3整除。如{1, 5, 1, 5, 1, 5}从二进制上看有:
1:0001
5:0101
1:0001
5:0101
1:0001
5:0101
二进制第0位上有6个1,第2位上有3个1.第1位和第3位上都是0个1,每一位上的统计结果都可以被3整除。而再对该数组添加任何一个数,如果这个数在二进制的某位上为1都将导致该位上1的个数不能被3整除。因此通过统计二进制上每位1的个数就可以推断出x在该位置上是0还是1了,这样就能计算出x了。
推广一下,所有其他数字出现N(N>=2)次,而一个数字出现1次都可以用这种解法来推导出这个出现1次的数字。
代码如下:
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
/** @brief
* 数组nums中,x出现一次,其他数字都出现了k次 * 以O(1)的空间复杂度,找出x * * @param nums[] int -元素数组 * @param len int -数组长度 * @param k int -除待求数组外,其他元素出现k次 * @return int -返回唯一出现一次的元素 * */ int GetUniqueValue(int nums[], int len, int k) { int bits[32]; memset(bits, 0, sizeof(bits)); /**< 统计数组中所有元素在某一位上1的个数 */ unsigned int flag = 1; for(int i = 0; i < len; ++i) { for(int j = 0; j < 32; ++j) // bits[31]保存的是符号位 { bits[j] += ((nums[i] & flag) ? 1 : 0); flag = flag << 1; } } /**< 去除出现k次的数据 */ for(int i = 0; i < 32; ++i) { if(bits[i] % k != 0) bits[i] = 1; } /**< 由于负数存储的是补码,这里将其转换为原码 */ bool isNegative = bits[31]; if(isNegative) { int idx = 0; while(idx < 31 && bits[idx] != 1) ++idx; // 由低位到高位找到第一个为1的位置 ++idx; // 从第一个1之后的位置开始变换(不变换符号位) while(idx < 31) bits[idx++] ^= 1; // 0与1互换 } /**< 根据二进制位及符号位计算该元素的值 */ int ret = 0; for(int i = 30; i >= 0; --i) { ret = ret * 2 + bits[i]; } if(isNegative) ret = -ret; return ret; } |