【剑指offer】数组中只出现一次的数字

思路真的很巧妙。

为什么要强调剩下的数字都出现了两次,而不是出现多次?

考虑到每个数字,自己和自己异或结果是0。

把数组中所有数字做异或,重复出现的数字被消掉了,最后的结果是要求的两个只出现一次的数字的异或值。

因为要求的这两个只出现一次的数字一定不相同,所以它们的异或值一定有某些位是1。这两个待求的只出现一次的数就是在这一位上有差异。

于是我们就把看一下这个异或值哪一位有1,再按照这一位把所有的数字分成两拨。

我们把这两拨数字分别异或,最后得到的两个数字即为所求。因为两个待求数字一定是分在这两拨里面,剩下的数都是成双成对的一定会被消掉。

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        int len = data.size();
        if (len < 2) return;
        int tmp = 0;
        for (int i : data)
            tmp ^= i;
        int pos = find1Pos(tmp);
        *num1 = 0, *num2 = 0;
        for (int i : data)
            compute(pos, num1, num2, i);
    }
    int find1Pos(int t) {
        int res = 0;
        while ((( t & 1) == 0) && res < 8*sizeof(int)) {
            ++res;
            t = t >> 1;
        }
        return res;
    }
    void compute(int const pos, int *num1, int *num2, int i) {
        if (((i >> pos) & 1 )== 0)
            *num1 ^= i;
        else
            *num2 ^= i;
    }
};

代码写完总也过不去,最后发现是这句出了问题((t & 1) == 0),一开始我写的是t&1==0,因为&的算术优先级低于==所以结果不对。吃一堑长一智!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值