剑指Offer-56:数组中数字出现的次数

博客介绍了如何在整型数组中找出仅出现一次的两个数字。通过异或运算的性质,可以找到两个数字异或的结果,然后根据结果的1位划分数组,再次异或获取目标数字。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目一:数组中数字出现的次数

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度O(n),空间复杂度O(1)。

链接:

剑指Offer(第2版):P275

思路标签:

  • 算法:问题分步解决
  • 异或

解答:

  • 使用异或运算的一个性质:任何一个数字异或它自己都等于0;那么如果从头到尾依次异或数组中的每个数,最终即是只出现依次的数字;
  • 题中需要寻找两个只出现一次的数字,那么我们如果将原数组分成两个子数组,每个子数组中只包含一个数字,其他数字都是成对出现。
  • 首先对所有元素进行异或,得到的结果是两个只出现一次的数字异或的结果,因为两个数字不一样,所以异或的结果中肯定至少有一位1;
  • 我们以第一个1的位置是否出现1为划分,将数组分为两个子数组;
  • 分别对每个子数组进行元素异或,则可以得到两个只出现一次的数字。
  • 注意:不必进行子数组的分拆和组合,只要在第二次遍历整个数组的过程中,对每个元素进行一次属于哪个子数组的判断操作即可。
class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        int length = data.size();
        if(length <=0)
            return;

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

        unsigned int indexOf1 = FindFirstBitOf1(resultOR);

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

    unsigned int FindFirstBitOf1(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);
    }
};

题目二:数组中唯一只出现一次的数字

在一个数组中除一个数字只出现一次之外,其他数字都出现了三次。请找出哪个只出现一次的数字。

链接:

剑指Offer(第2版):P278

思路标签:

  • 算法:位运算

解答:

  • 除目标数字外其他数字都出现三次,那么其二进制表示的每一位(0或者1)也出现三次;
  • 所有数字每一位均相加,每一位的和均能被3整除,不能被三整除的那一位即为目标数该位为1的情况。
class Solution {
public:
    int FindNumberAppearingOnce(int numbers[], int length) {
        if (numbers == nullptr || length <= 0)
            return 0;

        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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值