数组中只出现一次的数字

版权所有,转载请注明出处,谢谢!
http://blog.csdn.net/walkinginthewind/article/details/8138766

题目一:

一个整型数组里除了1个数字只出现一次之外,其他的数字都出现了两次。请写出程序找出这个只出现1次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

这个很简单,通过异或就可以除掉相同的数字,到最后只剩下一个只出现一次的数字。

参考代码如下:

void FindNumAppearOnce(int data[], int length, int *num)
{
	if(data == NULL || length < 1)
		return;

	int xorAll = 0;
	for(int i = 0; i < length; i++)
		xorAll ^= data[i];

	*num = xorAll;
}

题目二:

一个整型数组里除了2个数字只出现一次之外,其他的数字都出现了两次。请写出程序找出这个2个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

这个也是使用异或的思想。
既然有两个不同的数字num1、num2,那么这两个数字至少有一位不同,异或结果肯定至少有一位是1(其他数字成对出现不影响异或结果),也就是异或结果为1的地方就是这两个数字对应的位不同的地方。假如异或结果第k为是1,那么num1和num2的第k位一个为0,一个为1。我们根据第k为是否为0把它们异或到不同的结果xor1和xor2中。到最后xor1中和xor2中就保存的是num1和num2(或num2和num1)。

参考代码如下:

void FindNumsAppearOnce(int data[], int length, int *num1, int *num2)
{
	if(data == NULL || length < 2)
		return;

	int xorAll = 0;
	for(int i = 0; i < length; i++)
		xorAll ^= data[i];

	int k = 0;
	while((xorAll & (1 << k)) == 0) k++;

	int xor1 = 0, xor2 = 0;
	for(int i = 0; i < length; i++)
		if(data[i] & (1 << k))
			xor1 ^= data[i];
		else
			xor2 ^= data[i];

	*num1 = xor1;
	*num2 = xor2;
}

题目三:

一个整型数组里除了3个数字只出现一次之外,其他的数字都出现了两次。请写出程序找出这3个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

这个就稍微复杂一点,但是思想仍然相同。
由于所有数字的异或结果可能是0,因此,我们不能直接从所有数字异或的结果中获取信息。
3个不同的数字num1,num2,num3,那么他们至少有两位是不完全一样的,也就是存在两个位置,有一个是0另外两个是1或者有一个是1另外两个0。这里我们对每一位都进行分别保留异或结果。使用xor1[32]和xor2[32],如果一个数的第k位为1就异或到xor1[k]中,如果第k位为0,就异或到xor2[k]中,同时我们记录第k位为1的数字的个数。
最后,对于xor1[k1]和xor2[k1],xor1[k2]和xor2[k2],会有这两个位置异或结果不为0。如果第k1个位置为1的数字的个数是奇数,那么xor1[k1]中就是一个只出现一次的数,我们设为num1,否则xor2[k1]中保存的是num1,同样k2位置xor1[k2]和xor2[k2]有一个是num2,num3也可以求出来了,所有数字异或然后再异或一次num1和num2,剩下的就是num3。

参考代码如下:

void FindNumsAppearOnce(int data[], int length, int *num1, int *num2,int *num3)
{
	if(data == NULL || length < 3)
		return;
	const int INT_BITS = sizeof(int)*8;
	int xor1[INT_BITS], xor2[INT_BITS], cnt1[INT_BITS];
	memset(xor1,0,sizeof(xor1));
	memset(xor2,0,sizeof(xor2));
	memset(cnt1,0,sizeof(INT_BITS));
	int i, k, xorAll = 0;
	for(i = 0; i < length; i++)
	{
		for(k = 0; k < INT_BITS; k++)
		{
			if(data[i] & (1 << k))
			{
				xor1[k] ^= data[i];
				cnt1[k]++;
			}
			else
				xor2[k] ^= data[i];
		}
		xorAll ^= data[i];
	}
	k = 0;
	while(k < INT_BITS)
	{
		if(xor1[k]  && xor2[k])
		{
			if(cnt1[k] & 1)
				*num1 = xor1[k]; 
			else
				*num1 = xor2[k]; 
			break;
		}
		k++;
	}
	k++;
	while(k < INT_BITS)
	{
		if(xor1[k]  && xor2[k])
		{
			if(cnt1[k] & 1)
				*num2 = xor1[k]; 
			else
				*num2 = xor2[k]; 
			break;
		}
		k++;
	}
	*num3 = xorAll ^ (*num1) ^ (*num2);
}

但是,此方法的空间复杂度并不是O(1),而是O(logINT_BITS。我们要继续想办法。

请参考http://zhedahht.blog.163.com/blog/static/25411174201283084246412/


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值