zoukankan      html  css  js  c++  java
  • 数组中只出现一次的数

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

    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;
    }
  • 相关阅读:
    linux下解除端口占用
    设计模式(二)观察者模式
    设计模式(一) 策略模式
    loj #6235. 区间素数个数
    loj #2013. 「SCOI2016」幸运数字
    loj #6014. 「网络流 24 题」最长 k 可重区间集
    loj #6013. 「网络流 24 题」负载平衡
    loj #2255. 「SNOI2017」炸弹
    loj #2051. 「HNOI2016」序列
    loj #6122. 「网络流 24 题」航空路线问题
  • 原文地址:https://www.cnblogs.com/fengkang1008/p/4855481.html
Copyright © 2011-2022 走看看