在一组数中找到两个只出现一次的数字

今天要和大家分享的是我最近做到的一个比较有趣的编程问题,希望对大家有所裨益,话不多说下面开始进入正题。

简单版本题目及解决

给定一个只包含整数的数组 nums ,每个元素都会出现两次,唯有一个数只会出现一次,请找出这个唯一的数字。

这是今天要讲解的问题的简化版本,也就是使用在一堆出现两次的数中找到那个只出现一次的数字,是不是有种在一堆情侣中找到一条单身狗的感觉。

在正式讲解题目之前我们先来了解一个单目操作符——^,异或操作。这个操作符的作用是对两个数字的二进制下的每一位进行操作,如果这一位两个数字相同(都是1或者都是0),那么结果的这一位就是0,如果这一位两个数不同(一个是1,另一个是0),那么结果的这一位就是1。

 

如图所示,是异或操作的结果,a和b上每一位相同的,到结果上就变为0,反之就变为1。

那么我们就能理解一件事,如果两个相同的数异或,那么结果一定为0,因为两个相同的数的每一位必定相同。

我们还可以得出一个结论,0和任何数字异或,得到的结果还是这个数字,因为0的每一位都是0,这个数字上的某一位如果是零,和0异或之后还是0,如果是1,异或之后还是1.

那么我们就可以轻易地得到这道题的解法,把数组中的数字全部异或,得到的结果就是我们想要的结果。

#include<stdio.h>
//找到唯一的数
int singleNonDuplicate(int* parr,int nums)
{
    int ret = 0;
    int i = 0;
    //对数组中每一个数字进行异或操作
    for (i = 0;i < nums;i++)
    {
        ret = ret ^ *(parr + i);
    }
    //输出异或结果
    return ret;
}
int main()
{
    int arr[] = { 1,2,3,4,5,4,3,2,1,6,6 };
    int i = 0;
    int number1 = sizeof(arr) / sizeof(arr[0]);
    for (i = 0;i < number1;i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    printf("%d", singleNonDuplicate(arr, number1));
    return 0;
}

加深难度

那么我们对第一个问题加深难度,如果我们想要找到一个数组中的两个只出现一次的数字怎么办呢?

将所有数组异或的操作显然是不可取的,这只会得到一个两个只出现一次数字相互异或之后的结果。

我们需要把问题拆解,把一个数组分为两个数组,两个数组中分别包括两个只出现一次的数字,接下来睁大眼睛看是怎么操作的。

拆分数组

首先我们需要将所有数字异或,最后得到的结果是两个只出现一次数字的异或结果,这时结果二进制位中为1的位,就是两个数字的不同的地方,也就是我们可以以此为依据划分,保证我们想要的两个结果不会被分到一起。

异或求解

然后,就可以像解第一道题一样解决第二题了。

附上代码

#include<stdio.h>
//找到唯二的数
void singleNonDuplicate(int* parr,int nums,int* pc)
{
    int temp = 0;
    int ret[2] = {0,0};
    int i = 0;
    int j = 0;
    //对数组中每一个数字进行异或操作
    for (i = 0;i < nums;i++)
    {
        temp = temp ^ *(parr + i);
    }
    //获取第i位为1
    for (i = 0;i < 32;i++)
    {
        if (1&(temp >> i))
        {
            break;
        }
    }
    //分组异或
    for (j = 0;j < nums;j++)
    {
        if (1 & (parr[j] >> i))
            ret[0] = ret[0] ^ parr[j];
        else
            ret[1] = ret[1] ^ parr[j];
    }
    
    *pc = ret[0];
    *(pc + 1) = ret[1];//输出异或结果
}
int main()
{
    int arr[] = { 1,2,3,4,5,4,3,2,1,6,6,8};
    int i = 0;
    int number1 = sizeof(arr) / sizeof(arr[0]);
    int ret[2] = { 0,0 };
    singleNonDuplicate(arr, number1, ret);
    for (i = 0;i < number1;i++)
    {
        printf("%d ", arr[i]);
    }
    printf("\n");
    printf("%d ", *ret);
    printf("%d", *(ret +1));
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JDSZGLLL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值