只出现一次的数字 III

题目:见下图

答案:见下图

int* singleNumber(int* nums, int numsSize, int* returnSize) {
    int ret = 0;
    for (int i = 0; i < numsSize; i++) {
        ret ^= nums[i];
    }
    // 找第m位数,以区分
    int m = 0;
    while (m < 32) 
    {
        if (ret & (1 << m))
            break;
        else
            m++;
    }

    // 分离
    int x1 = 0, x2 = 0;
    for (int i = 0; i < numsSize; i++) {
        if (nums[i] & (1 << m)) {
            x1 ^= nums[i];
        } else {
            x2 ^= nums[i];
        }
    }
    //储存
    int* retArr = (int*)malloc(sizeof(int) * 2);
    retArr[0] = x1;
    retArr[1] = x2;

    *returnSize = 2;

    return retArr;
}

解析:

在做此题前我们需要先补充一些知识

1.异或是一种二进制的位运算

符号以 ^ 表示,相同为0,不同为1

任何二进制数与零异或,都会等于其本身,即 A ^ 0 = A

2.按位与"&"功能是参与运算的两数各对应的二进位相与,只有对应的两个二进位均为1时,结果位才为1 ,否则为0

3.左移(<<):0011 << 1 = 0110

右移(>>):0110 >> 1 = 0011

(1)将数组nums与0进行异或

当我们得到整形数组nums,我们为了进行分离数,可以将数组与0进行异或,这样出现两次的数就会被消除,仅留下仅出现一次的数ret

    int ret = 0;

    for (int i = 0; i < numsSize; i++) {

        ret ^= nums[i];

    }

(2)找出为一的位次m

异或后的数ret以二进制的形式进行储存,二进制共32位,根据异或规则,不同为1,当第m位次两个仅出现一次的数,一个为0一个为1,异或结果为1,那么我们就可以找出任意一位位次为一的位次m,

    int m = 0;

    while (m < 32)

    {

        if (ret & (1 << m))

            break;

        else

            m++;

    }

(3)将数组根据m位次分组

将数组nums的元素进行分离至x1,x2,此时两个仅出现一次的数,两数m位次不相同一个为0,一个为1,必然会一个分到x1,一个分到x2,将其用&进行判断,分组

并且将储存进入x1,x2的数字与0进行异或,此时x1,x2出现两次的数都被异或掉了,仅留下两个出现一次的数

    int x1 = 0, x2 = 0;

    for (int i = 0; i < numsSize; i++) {

        if (nums[i] & (1 << m)) {

            x1 ^= nums[i];

        } else {

            x2 ^= nums[i];

        }

    }

(4)开辟数组储存出现一次的数字

这里需要有需要补充malloc函数知识

开辟空间用malloc函数,其头文件是#include <malloc.h> 

malloc函数用法 : 指针自身 = (指针类型*)malloc(sizeof(指针类型)*数据数量)

开辟数组我们使用malloc函数,并且将x1与x2分别储存到新开辟的数组retArr中

返回元素个数2,返回开辟的新数组retArr

    int* retArr = (int*)malloc(sizeof(int) * 2);

    retArr[0] = x1;

    retArr[1] = x2;

   *returnSize = 2;

    return retArr;

到这里我们解题完毕

如果对您有帮助的话点一个免费的赞和收藏叭!

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值