面试题56: 数组中数字出现的次数

/*******************************************************************
*《剑指Offer——名企面试官精讲典型编程题》C++代码
*
* htfeng
* 2018.10.09
*
* 面试题56: 数组中数字出现的次数
* 题目一:数组中只出现一次的两个数字
*
* 题目一分析: 
* 相关数字的二进制表示为:
* 2 = 0010       3 = 0011       4 = 0100
* 5 = 0101       6 = 0110
*
* 步骤1 全体异或:2^4^3^6^3^2^5^5 = 4^6 = 0010
* 步骤2 确定位置:对于0010,从右数的第二位为1,因此可以根据倒数第2位是否为1进行分组
* 步骤3 进行分组:分成[2,3,6,3,2]和[4,5,5]两组
* 步骤4 分组异或:2^3^6^3^2 = 6,4^5^5 = 4,因此结果为4,6。
* 
* 题目二: 数组中唯一只出现一次的数字
*
* 分析: 基于位运算,若一个数字出现三次,那么它的二进制表示中的每一位也出现三次。把
* 数组中的所有出现三次的数字的二进制表示的每一位分别加起来,则每一位的和都能被3整除,
* 再把所求的那个数字的每一位分别加上去,若二进制对应位的和还能被3整除,则所求数字对
* 应位为0,否则为1。最终,得到所求数字的二进制表示。

********************************************************************/

class Sulotion {
public:
    // 题目一:数组中只出现一次的两个数字
    unsigned int FindFirstBitIs1(int num) {
        int indexBit = 0;
        while (((num & 1) == 0) && (indexBit < 8 * sizeof(int))) {
            num = num >> 1;
            ++indexBit;
        }

        return indexBit;
    }

    bool IsBit1(int num, unsigned int indexBit) {
        num = num >> indexBit;
        return (num & 1);
    }

    void FindNumsAppearOnce(int data[], int length, int* num1, int* num2) {
        if (data == nullptr || length < 2)
            return;

        int  resultExclusiveOR = 0;
        for (int i = 0; i < length; ++i)
            resultExclusiveOR ^= data[i];

        unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);

        *num1 = *num2 = 0;
        for (int j = 0; j < length; ++j) {
            if (IsBit1(data[j], indexOf1))
                *num1 ^= data[j];
            else
                *num2 ^= data[j];
        }
    }

    // 题目二: 数组中唯一只出现一次的数字
    int FindNumberAppearingOnce(int numbers[], int length) {
        if (numbers == nullptr || length <= 0)
            return -1;

        int bitSum[32] = { 0 };
        for (int i = 0; i < length; ++i) {
            int bitMask = 1;
            for (int j = 31; j >= 0; --j) {
                int bit = numbers[i] & bitMask;
                if (bit != 0) {
                    bitSum[j] += 1;
                    bitMask = bitMask << 1;
                }
            }

            int result = 0;
            for (int i = 0; i < 32; ++i) {
                result = result << 1;
                result += bitSum[i] % 3;
            }

            return result;
        }
    }

};

转载于:https://www.cnblogs.com/htfeng/p/9933503.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值