C语言----单身狗问题

单身狗版本1

1.题目描述

        一个数组中只有一个数字出现一次,其余数字均是成对出现,请找出只出现一次的数字。例如:{1,1,2,2,3,3,4,4,5},那么这个数字就是5。

2.解题思路

        我们采用异或法解决,首先我们先来看异或的定义:异或指的是二进制中,对应的二进制位相同时异或为零,相异时异或为一,且异或还具有交换律。

  • a^a=0 (和自身异或值为0)
  • a^0=a (和0异或值为自身)
  • a^b^a=a^a^b (异或满足交换律)

异或具有如上性质,那么单身狗问题就是数组中的值自身异或,成对出现的异或为0,最后0和只出现一次的数字异或,得到数字本身。最终得到的值就是只出现过一次的值。

3.代码实现
int find_single_dog1(int arr[], int sz)
{
	int ret = 0;
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		ret ^= arr[i];
	}
	return ret;
}
int main()
{
	int arr[] = { 1,1,2,3,4,4,3,5,5 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int dog = find_single_dog1(arr, sz);
	printf("%d\n", dog);
	return 0;
}

单身狗版本2 

1.题目描述

        一个数组中只有两个数字是单独出现一次,其余数字均是成对出现,请找出这两个只出现了一次的数字。例如:数组元素为:1,1,2,2,3,3,4,4,5,6.那么这两个数字就是5和6.

2.解题思路

        我们还是使用异或法,但我们需要思考一个问题,两个数字的话我们怎样进行异或?我们这样思考,当把数组中所有的数字异或时,得到的结果是两个只出现一次数字的异或,以上面的数组为例,异或得到的结果就是5^6,那我们将原始数组进行分组,把5和6分开,再让两个分开后的数组自己异或,就能得到结果。思路总结如下:

  • 分成两个组,每个组都有一个单独出现的数字。
  • 相同的数字必须在同一个组。

 以上面数组为例,5的二进制位是101,6的二进制位是110,我们可以按照第一位0或1进行分类,第一位为1的数组可分为1 1 3 3 5,第一位为0的数组可分为2 2 4 4 6,于是我们就完成了分类,假如第一位是相同的,那么我们就可以找第二位0或1进行分类。

        再来学习一个运算符:右移运算符(>>)定义:将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。

3.代码实现

        这段代码函数核心是3个功能,第一个功能找到原本数组异或后的结果,把这个结果保存下来,以上面数组为例:异或相异为1,那么上面101^110就是011。第二个功能找到结果中两个数不同的位,并把它用pos变量记录下来,011>>0再&1,结果就是1,所以pos为1。第三个功能根据位数上不同的0和1进行分类。最后把得到的dog1和ret再异或,就得到了dog2,如:5^5^6=6。

void find_single_dog2(int arr[], int sz,int* pd1,int* pd2)
{
	int ret = 0;
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		ret ^= arr[i];
	}
	int pos = 0;
	for (i = 0; i < sz; i++)
	{
		if (((ret >> i) & 1) == 1)
		{
			pos = i;
			break;
		}
	}
	for (i = 0; i < sz; i++)
	{
		if (((arr[i] >> pos) & 1) == 1)
		{
			*pd1 ^= arr[i];
		}
	}
	*pd2 = ret ^ *pd1;
}
int main()
{
	int dog1 = 0;
	int dog2 = 0;
	int arr[] = { 1,1,2,2,3,3,4,4,5,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	find_single_dog2(arr, sz,&dog1,&dog2);
	printf("%d %d\n", dog1,dog2);
	return 0;
}

C语言----单身狗问题_第1张图片

 

你可能感兴趣的:(c语言,算法,数据结构)