【C语言】一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。 找出这两个数字,编程实现。

一看到这道题,我想到了之前学习过的异或。我们知道两个相同的数字异或的结果是 0,因为在计算机中,异或运算是按照二进制位来运算的,相同为 0 ,相异为  1 任何数与 0 异或都等于它自己。既然我们要找出来一组数中不同的两个数字,也可以采用这种方法。

但是这次不是直接异或,而是要分组。将数组的数据分成两组,把这两个不一样的数分到两个组里,这样最后的异或结果就是这两个数了。那么具体怎么做呢?

第一步  所有数字异或

我们先将所有的数字异或一遍,结果存储在num中。

第二步  找num的二进制位中的1的位置

因为根据异或法则,相同为 0 ,相异为 1,那么如果两个数异或的结果num中二进制位中有1,就说明这两个数字不一样。这样问题就变成找num二进制位中的1,遍历32次就可以检查所有位。一旦找到一个位是1,我们便出循环不再查找,因为已经可以证明这两个数不一样了。接着我们可以将这个结果存储在pos中,以便分组。

第三步  按照pos位为0或者1分组

根据第二步,找到1就跳出来保存为pos,那么我们再来一个循环,判断所有数字异或后的结果,如果是1,分为一个组,否则,进入另一个组。

这样做,直到最后,所有的数字异或结束,相同的为 0,不同的则是这个数。具体代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>

void find_diff_num(int *arr, int sz,int* px,int* py)
{
//1.所有数字异或
	int num = 0;
	int i = 0;
	int pos = 0;
	for (i = 0; i < sz; i++)
	{
		num ^= arr[i];
	}

//2.找num的二进制位中的1的位置
	for (i = 0; i < 32; i++)
	{
		if (((num >> i) & 1) == 1)
		{
			pos = i;
			break;
		}
	}
//3.按照pos位为0或者1分组
	for (i = 0; i < sz; i++)
	{
		if (((arr[i] >> pos) & 1) == 1)
		{
			*px ^= arr[i];
		}
		else
		{
			*py ^= arr[i];
		}
	}
}


int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 1, 2, 3, 4, 6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int n1 = 0;
	int n2 = 0;
	find_diff_num(arr,sz,&n1,&n2);
	printf("%d %d", n1, n2);
	system("pause");
	return 0;
}


  

猜你喜欢

转载自blog.csdn.net/Miss_Monster/article/details/81537288