[C语言]一个数组中只有两个数字是出现一次,其他所有数字都出现了两次,编写一个函数找出这两个只出现一次的数字。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


题目

一个数组中只有两个数字是出现一次,其他所有数字都出现了两次,编写一个函数找出这两个只出现一次的数字。

解题思路

前提条件

异或的特点就是两个相同的数字进行异或,得到的结果为0。任何数与0异或是其本身。

第一步

我们可以把所有的数字异或一遍,最终得到的就是两个单身狗数的异或结果。
假设 ar[] = { 1,2,3,4,5,1,2,3,4,6 },其中不同的是5,6,用temp存储。
假设  ar[] = { 1,2,3,4,5,1,2,3,4,6 },其中不同的是5,6,用temp存储。

第二步

为将众数字分成两份,只需要根据temp上任意1的位置就可以区分5,6,然后区分别的数字
定义一个mask,使mask取temp上的任意一位1
(找到其结果任意二进制为1(异或结果不同才会为1)的一位赋值给mask)

int mask = 0x01;
	//0000 0001
	//0000 0011  temp
	
while ((mask & temp) == 0)
	mask <<= 1;
	//0000 0001  mask & temp第一次!=0 跳出循环

第三步

将每个数字与mask 按位与 将数字分为两部分,然后就是要将两组数各自组内 异或 就可以得到两个单身狗数。

代码呈现

#define _CRT_SECURE_NO_WARNINGS  1
#pragma warning(disable:6031)
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>


//        单身狗2
//一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
//编写一个函数找出这两个只出现一次的数字。
//
//例如:
//
//有数组的元素是:1,2,3,4,5,1,2,3,4,6
//只有5和6只出现1次,要找出5和6.

//解题思路:
//异或的特点就是两个相同的数字进行异或,得到的结果为0
//任何数与0异或是其本身。

//我们可以把所有的数字异或一遍,最终得到的就是两个单身狗数的异或结果。
//假设  ar[] = { 1,2,3,4,5,1,2,3,4,6 },其中不同的是5,6,用temp存储。

//为将众数字分成两份,只需要根据temp上任意1的位置就可以区分5,6,然后区分别的数字
//将每个数字与mask ==按位与== 将数字分为两部分,然后就是要将两组数各自组内 ==异或== 就可以得到两个单身狗数。

int* FindNum2(int arr[], int n)
//不需要int* arr[],因为我们的目的自是找出数字就行,不需要对原数组进行修改,临时地址就够用
{
	int temp = 0;
	for (int i = 0; i < n; i++)
		temp ^= arr[i];
	//5    0101
	//6    0110
	//temp 0011
	int mask = 1;
	while ((mask & 1) == 0)
		mask << 1;
	//mask   0X0001
	//temp   0X0011
	//此时就已经mask & temp != 0
	// 所以 mask   0X0001

	int* res = (int*)calloc(2, sizeof(int));
	//必须创建指针数组,不然临时变量等运行结束会消失
	//通过动态内存的方式创建两个int大小内存空间
	assert(res != NULL);

	for (int i = 0; i < n; ++i)
	{
		if ((arr[i] & mask) != 0)
			res[0] ^= arr[i];//res[0] = 0 ^ 1^ 5^ 1 = 5
		else
			res[1] ^= arr[i];//res[1] = 0 ^ 6 ^4 ^4 = 6
	}

	return res;
	//因为这两个地址相连,直接传回去就行
}


int main()
{
	int ar[] = { 1,2,3,4,5,1,2,3,4,6 };
	int n = sizeof(ar) / sizeof(ar[0]);
	int* res = FindNum2(ar, n);
	//创建指针接收地址
	int sz = 2;
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", res[i]);
	}

	return 0;
}
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值