找单身狗(两只)的两种解法

问题

找出数组1,2,3,4,5,6,1,2,3,4中的两只单身狗,单身狗是指数组中的只出现过一次的数字。

构思

首先我们可以思考,如果只有一只单身狗是否就容易找出了呢?如果容易找出,那么我们只需要把每一只单身狗分到不同的两个组就好。然后再对这两个组别分别寻找单身狗。

如何从只有一只单身狗的数组中找到单身狗

众所周知当两个相同的数字相互异或(^),结果会是0;而当一个数异或(^)0时结果会是数字本身。知道方法后我们便开始尝试从数组1,2,3,4,5,1,2,3,4中找出5。从图片中可以清晰看出当所有数字相互异或之后会等于5,也就是这个数组中的单身狗。

根据这个逻辑我们写出代码

int c = 0;
for (int j = 0; j < sizeof(arr) / sizeof(int); j++)//数组中所有的数分别异或
{
	c ^= arr1[j];
}

又因为我们到时候分组后会有两组,所以我们代码中要有两组数组对自己进行异或

for (int j = 0; j < sizeof(arr) / sizeof(int); j++)//两个数组都异或上自己
{	c ^= arr1[j];
	d ^= arr2[j];
}

从只有一个单身狗的数组中找到单身狗的方法我们已经发现。现在我们要找到一个办法来把两个单身狗分成两组。

分组的办法

我们知道两个不同数的二进制是不可能一模一样的,至少会有一位数上有区别,比如题中的5和6,二进制分别为0b101和0b110,他们在第一位上就不同,当然第二位也不同。但是我们只需要找到他第一个不同的数然后将原数组按照这个位上分组就好了。如图所示:

那如何找到这一位上的不同呢。我们可以让原来的数组相互异或,得出单身狗相互异或的值,然后对这个数与1按位与然后和1相互比较,每次1向左移位1步,我们就把1这个变量设为i,如果结果还为i,那么就能得出i的值,再拿这个i值和数组中的数想与,就能分出数组中在这位上同和不同的数。

	for ( i = 1; (a & 1) != i; i << 1);//找出单身狗第一个不同位上的数,如110和101那第一个
	int arr1[10] = { 0 };              //不同位就是001
	int arr2[10] = { 0 };
	for (int j = 0; j < sizeof(arr) / sizeof(int); j++)
	{
		if ((arr[j] & i) == i)//按照单身狗第一个不同位上的数分类,分为两组使每一组只有一个单身狗
			arr1[j] = arr[j];
		else
			arr2[j] = arr[j];
	}

最后我们把上述代码合并,得出总代码。

int main()//找单身狗
{
	int arr[] = { 1,2,3,4,5,6,4,3,2,1 };
	int a = 0;
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)//求出单身狗的不同位(不同位为1)如:
	{                                                  //110^101之后为011,那不同位就是第二第三位
		a ^= arr[i];
	}
	int i;
	for ( i = 1; (a & 1) != i; i << 1);//找出单身狗第一个不同位上的数,如110和101那第一个
	int arr1[10] = { 0 };              //不同位就是001
	int arr2[10] = { 0 };
	for (int j = 0; j < sizeof(arr) / sizeof(int); j++)
	{
		if ((arr[j] & i) == i)//按照单身狗第一个不同位上的数分类,分为两组使每一组只有一个单身狗
			arr1[j] = arr[j];
		else
			arr2[j] = arr[j];
	}
	int c = 0,d=0;
	for (int j = 0; j < sizeof(arr) / sizeof(int); j++)//两个数组都异或上自己
	{
		c ^= arr1[j];
		d ^= arr2[j];
	}
	printf("%d %d\n", c, d);
}

运行一下试试

我们发现可以直接找到5和6了。

当然这种方法非常麻烦,步骤也比较复杂,所有我还有一个简便一些的方法。

找单身狗方法二

我们可以创建一个空间,在这个空间里按照原数组的内容分配这块空间的内存。

如图所示:

我们可以将上述逻辑按照三步执行,一步是找到原数组的最大值,一步是按照原数组的值使空间内的值加一(这里不初始化空间内容为0是因为calloc会自动初始化),最后一步是找到数组值为1的下标。

第一步代码:

int arr[] = { 1,2,3,4,5,6,1,2,3,4 };
int i, max = arr[0]; int sz = sizeof(arr) / sizeof(int);
for (i = 1; i < sz; i++)//找到最大的那个数
{
	if (arr[i] > max)
		max = arr[i];
}

第二步代码:

int sz1 = i;
int* phaxi = (int *)calloc(i, sizeof(int));
if (phaxi == NULL)
{
	perror("容量");
}

for (i = 0; i < sz; i++)
{
	(*(phaxi + arr[i]))++;
}

第三步代码:

for (i = 0; i < sz1; i++)
{
	if (*(phaxi + i) == 1)
		printf("%d ", i);
}

当然代码写完了不能忘了释放calloc所给的空间。(这是一个良好的习惯,防止造成内存泄漏)

free(phaxi);
phaxi = NULL;

最后我们看一下整体的代码

#include<stdlib.h>
int main()//找单身狗哈希法
{
	int arr[] = { 1,2,3,4,5,6,1,2,3,4 };
	int i, max = arr[0]; int sz = sizeof(arr) / sizeof(int);
	for (i = 1; i < sz; i++)//找到最大的那个数
	{
		if (arr[i] > max)
			max = arr[i];
	}
	int sz1 = i;
	int* phaxi = (int *)calloc(i, sizeof(int));
	if (phaxi == NULL)
	{
		perror("容量");
	}
	
	for (i = 0; i < sz; i++)
	{
		(*(phaxi + arr[i]))++;
	}
	for (i = 0; i < sz1; i++)
	{
		if (*(phaxi + i) == 1)
			printf("%d ", i);
	}
	free(phaxi);
	phaxi = NULL;

}

运行后我们可以看到代码工作正常,完工!!!!!!!!! 

谢谢大家能观看到这,本人是新人,希望各位大佬多多担待,喜欢的话点个关注哟!!!!再次感谢大家。

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值