Cracking code interviews_1

题目

数组A中,除了某一个数字x之外,其他数字都出现了三次,而x出现了一次。请给出最快的方法,找到x。

分析

乍一看这个题目,不少同学立马给出了答案:异或。但举个例子,就会发现,异或是行不通的,一般的方法是利用异或的的如下特性:

A xor A = 0

A xor 0 = A

但是这个题目中,数字都是奇数个的,直接采用之前类似题目的异或方法,已经不合适了。

除此之外,我们还可能想到如下的方法:

采用hashmap,时间复杂度O(n),空间复杂度O(n)

对数组A进行排序,然后在遍历一次,时间复杂度O(nlogn),空间复杂度O(1) 这个方法还可以。

是否还有一些效果更好的方法呢?这一类的题目,即使简单的异或不能解决,也可以从二进制位、位操作方面去考虑,总之这样的大方向是不会错的。

题目中,如果数组中的元素都是三个三个出现的,那么从二进制表示的角度,每个位上的1加起来,应该可以整除3。如果有一个数x只出现一次,会是什么情况呢?

如果某个特定位上的1加起来,可以被3整除,说明对应x的那位是0,因为如果是1,不可能被3整除

如果某个特定位上的1加起来,不可以被3整除,说明对应x的那位是1

根据上面的描述,我们可以开辟一个大小为32的数组,第0个元素表示,A中所有元素的二进制表示的最低位的和,依次类推。最后,再转换为十进制数即可。这里要说明的是,用一个大小为32的整数数组表示,同样空间是O(1)的。

代码如下:

#include <stdio.h>
#include <stdlib.h>
/*
* author: grant. alliswell 
* mail: *****@mail.ustc.edu.cn
*/

// //
// find one number which only appear once in an array
// input: data - an array contains one number appearing only once,
//        while others appearing exactly third.
//         length - the length of data
// output: num
/////////////////////////////////////////////////////////////////////////  

// set i-th bit in num as 1 
void set(int &a, int i){
    a |= (1 << i); 
}

// set the i-th in num as 0

void clear(int &a, int i){
    a &= (~(1 << i));
}

// find the number apperaing only once in data

void FindNumAppearOnce(int data[], int length, int &num){
    int Bits[32];

    for (int i = 0; i < 32; ++i){
        Bits[i] = 0;
        for (int j = 0; j < length; j++){
            if (data[j] & (1 << i))
                Bits[i] += 1;
        }
    }

    num = 0;
    for (int i = 0; i < 32; i++) 
       if ((Bits[i] % 3) == 1) 
           set(num, i);    
}


int main(){
    int data[16] = {1,1,1,2,2,2,3,3,3,4,4,4,9,10,10,10};

    int num = 0;
    FindNumAppearOnce(data, 16, num);

    printf("The num appearing only once is: %d", num);
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值