剑指offer——数组中只出现一次的数字

1、一个数字出现一次,其他数字出现两次

两个相同的数异或为0,所以将数组里的所有数依次异或,得到的结果就是只出现一次的数。

#include <iostream>
using namespace std;
int main()
{
	int a[]={3,6,2,3,2,5,5};
	int num=0;
	for(int i=0;i<7;i++)
	{
		num^=a[i];
	}
	cout<<num<<endl;
	return 0;
}

2、一个数字出现一次,其他数字出现N次

通过观察法,发现如果数字出现了n次,那么每一bit位之和可以被n整除。

#include <iostream>
#include <string>
using namespace std;
int FindNumber(int a[], int n, int m)
{
  int bits[32];
  int i, j;
  // 累加数组中所有数字的二进制位
  memset(bits, 0, 32 * sizeof(int));
  for (i = 0; i < n; i++)
    for (j = 0; j < 32; j++)
      bits[j] += ((a[i] >> j) & 1);
  // 如果某位上的结果不能被整除,则肯定目标数字在这一位上为
  int result = 0;
  for (j = 0; j < 32; j++)
    if (bits[j] % m != 0)
      result += (1 << j);
  return result;
}
int main()
{
  int a[] = {2, 3, 1, 2, 3, 4, 1, 2, 3, 1};
  //3代表其他数字出现3次
  cout<<FindNumber(a, 10, 3)<<endl;
  return 0;
}

3、两个数字出现一次,其他数字出现两次

和1的原理差不多,先是分别异或,得到结果,肯定不为0。找到结果1所在的位置x,将原数组分为两部分,第一部分是x为1的数的集合,第二部分是x为0的数的集合。然后分别对这两个数组异或,得到这两个出现一次的数。

#include <iostream>
#include <string>
using namespace std;

unsigned int FindFirstBitIs1(int num)
{
	int indexBit=0;
	while(((num&1)==0)&&(indexBit<8*sizeof(int)))
	{
		num=num>>1;
		++indexBit;
	}
	return indexBit;
}

bool IsBit1(int num,unsigned int indexBit)
{
	num=num>>indexBit;
	return (num&1);
}

void FindNumsAppearance(int data[],int length,int *num1,int *num2)
{
	if (data==NULL||length<2)
	{
		return;
	}
	int resultExclusiveOR=0;
	for (int i=0;i<length;i++)
	{
		resultExclusiveOR^=data[i];
	}
	unsigned int indexof1=FindFirstBitIs1(resultExclusiveOR);
	*num1=*num2=0;
	for (int j=0;j<length;j++)
	{
		if (IsBit1(data[j],indexof1))
		{
			*num1^=data[j];
		}
		else
		{
			*num2^=data[j];
		}
	}
}

int main()
{
	int a[]={4,3,6,3,2,5,5};
	int temp1,temp2;
	FindNumsAppearance(a,7,&temp1,&temp2);
	cout<<temp1<<"\t"<<temp2<<endl;
	return 0;
}

参考:

http://blog.csdn.net/morewindows/article/details/12684497

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值