【剑指Offer-知识迁移能力】面试题56:数组中只出现一次的两个数字

题目描述

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

思路

假设一个数组中有 3 个数字,其中两个数字相同,那么这3个数字异或的结果就是那个只出现一次的数字,例如数组为 [1,2,1],则 1^2^1=2。题目中给的数组中存在两个只出现一次的数字,所以我们需要把这个数组分成两部分,每部分包含一个只出现一次的数字。这样,对两个数组中的元素分别进行异或就能获得两个只出现一次的数字。

将数组分成两部分的方法:首先对数组中的全部元素进行异或,得到的结果记为 xorResult。因为数组中存在两个只出现一次的数字,所以 xorResult 不为 0,这意味着其二进制中至少有一位为 1。我们找到 xorResult 二进制中为 1 的那一位,记为第 n 位,然后我们根据数组中数字的二进制的第 n 位是 0 还是 1 将数组分为两部分。这样能保证出现两次的数字被分到同一个数组(因为相同的数字其二进制也相同),并且两个只出现一次的数字被分到了两个数组中(因为这两个数字的第 n 位必然不同,如果相同的话,第 n 位异或的结果就是 0 而不是 1 了)。代码如下:

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        if(data.empty())
            return;
        
        int xorResult = 0;
        for(int i=0; i<data.size(); i++)
            xorResult ^= data[i];
        
        int idx = 0;    //二进制中第一个1的下标
        while((xorResult&1)==0){
            xorResult = xorResult>>1;
            idx++;
        }
        
        *num1 = *num2 = 0;
        for(int i=0; i<data.size(); i++){
            if(is1AtIndex(data[i], idx))
                *num1 ^= data[i];
            else *num2 ^= data[i];
        }
    }
    
    bool is1AtIndex(int num, int idx){
        num = num>>idx;
        return (num&1);
    }
};
posted @ 2020-03-19 16:14  Flix  阅读(111)  评论(0编辑  收藏  举报