数组中只出现一次的数

位操作(应该是异或^),目前已知可解决以下问题:

  1. 数组中,一个元素只出现一次(奇数次),其他出现偶数次;
  2. 数组中,两个元素只出现一次(奇数次),其他出现偶数次;

解决方法详见这两篇博客:

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, 
0sizeof(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;
}
posted @ 2015-10-05 11:08  指上弹兵赵小括  阅读(406)  评论(0编辑  收藏  举报