40、数组中只出现一次的数字

题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

异或的方法。

先考虑一个简单一点的问题,数组里除了一个数字以外,其它都出现两次,找到这个数字。

这个题之前遇到过,做法是把数组里所有数字异或,最后得到的数字就是只出现一次的那一个数字。为什么是这样呢?因为异或运算有一个性质:任何一个数字异或它自己都等于0.所以将数组里的数字从头到尾异或,最后得到的一定是落单的那一个数字。

那么两个出现一次的问题怎么解决呢?如果可以把一个数组分成两半,每一半里都只有一个只出现一次的数,那就又变成了上面的问题。所以问题变成了我们怎么样可以把数组分成符合条件的两半?

由于相同的数异或得零,如果把数组里所有数异或,得到的将是这两个落单的数的异或值。由于这两个数肯定不相等,所以这两个数的异或值也不会为0。从右向左找到这个异或值不为零的一位,比如说是第N位,那么根据第N位是否为0把原数组分为两个部分。(异或的概念:两个数对应为相同为0,不同为1),也就是说,如果第N位异或结果为1,这两个数字的第N位一定不同。所以按照这个标准将数组分成两部分,将实现每一部分里只有一个落单的数。

代码:

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        if(data.size() < 2)
            return;
        int resOR = 0;
        for(int i = 0;i < data.size();i++){
            resOR ^= data[i];
        }
        unsigned int indexof1 = FindFirstBitIs1(resOR); 
        *num1 = *num2 = 0;
        for(int i = 0;i < data.size();i++){
            if(IsBit1(data[i],indexof1))
                *num1 ^= data[i];
            else
                *num2 ^= data[i];
        }
    }

    //找到num的二进制表示中找到最右边是1的位  
    unsigned int FindFirstBitIs1(int num){
        int indexBit = 0;
        while(((num & 1)==0) && indexBit < 8 * sizeof(int)){
            num = num >> 1;
            indexBit++;
        }
        return indexBit;
    }

    //判断在num的二进制表示中从右边数起的第indexBit位是不是1
    bool IsBit1(int num,unsigned int indexBit){
        num = num >> indexBit;
        return (num & 1);
    }
};

tips:取某数字的二进制数字的某一位的方法

int num;
num >> n;
num & 1;//得到的就是num从右边数第n位的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值