一个整型数组里除了两个数之外,其他数都出现了两次。找出这两个出现一次的数。

好久没写博客了,说明我好久没有努力了。好惭愧。

题目:一个整型数组里除了两个数之外,其他数都出现了两次。找出这两个出现一次的数。


一、第一个想法是借助辅助数组以及折半插入来实现。(原数组为vector<int >data)

思路:

1、创建两个数组一个大小均为 (data.size()-2)/2+2。也就是不包含重复数字的总个数。两个数组分别为

int arr[]用于存储数字,和int temp[] 用于记录是否重复。arr[0] = data[0],temp[0] = 0。

2、遍历原数组vector<int >data。通过折半插入放入数组int arr[]中。

3、在折半插入过程中,如果要插入的数在arr[]数组中已经存在,循环continue,同时把对用temp[i]设为-1,

表示arr[i]这个数出现过两次。如果插入的数在arr[]数组中不存在,则arr[]数组与temp[]数组同时执行后移。

4、之后再通过遍历temp[]数组,将 temp[i] != -1  对应arr[i]中的值分别赋值给num1,num2即可。整个过程

时间复杂度为O(N*logN)


代码:

//折半查找
int binarySeek(int *a,int begin,int end,int num,int *temp){
	int mid= begin+(begin+end)/2;
	while(begin<=end)
	{
		mid = begin+(end-begin)/2;
		if(a[mid]<num)
			begin = mid+1;
		else if(a[mid]>num)
			end = mid-1;
		else if(a[mid] == num)
		{
			temp[mid] = -1;
			return -1;
		}
	}
	return begin;
}

//插入排序
void insertSort(int *arr,vector<int> data,int *temp,int *num1,int *num2){
	int j=0;
	//遍历data数组
	for(int i=1;i<data.size();i++)
	{
		int num = data[i];
		int begin = 0;
		int end = j;
		//折半查找
		int set = binarySeek(arr,begin,end,num,temp);
		//待插入的值为重复值
		if(set == -1)
			continue;
		//待插入的值为新值,arr 与 temp 都要后移
		else
		{
			j++;
			int k = j;
			while(k>set)
			{
				arr[k] = arr[k-1];
				temp[k] = temp[k-1];
				k--;
			}
			arr[k] = num;
			temp[k] = 0;
		}
	}
	int m = 0;
	//遍历temp 寻找需求值
	for(int i=0;i<=j;i++)
	{
		if(temp[i]==0)
		{
			int a = arr[i];
			if(m ==0)
			{*num1 = a;m++;}
			else
				*num2 = a;
		}
	}
}

void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
                if(data.empty()||data.size()<2)
                    return ;
               int arrLength = (data.size()-2)/2+2;
		int *arr = new int[arrLength];
		int *temp = new int[arrLength];
		arr[0] = data[0];
		temp[0] = 0;
		//插入排序
		insertSort(arr,data,temp,num1,num2);
 }

二、第二个想法是通过 异或运算 实现   原数组为 vector<int >data

思路:

1、既然数组中除了两个不同的数出现一次之外,其他的数都出现过两次。则除了这两个数之外,

其他所有数经过异或运算得出的值为0。因此整个vector<int >data数组得到的异或值,就是所要求

的两个数的异或值。

2、由于这两个数不同,异或值一定不为0,在二进制表示中异或值必有一位(设第i位)为1,这个1,

意味两个数中一个数的第i位为0,另一个数的第i位为1。因此可以通过第i位为是否为1  把原数组data

分为两个数组,一个数组中所有数第i位为0,另一个数组中所有数第i位为1.

3、分别对两个数组进行异或运算,得到的两个值即所需要求的两个值。

时间复杂度为O(N)


代码:

//得到第i位作为分隔数组的条件
int getPosition(int xorNum){
	int position = 0;
	while((xorNum&1)==0&&position<32)
	{
		xorNum = xorNum>>1;
		++position;
	}
	return position;
}

//判断第i为是否为1
bool judge(int num,int position){
	num = num>>position;
	return (num&1)==1;
}


void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
	int a,b;
	a=b=0;
	if(data.empty()||data.size()<2)
		return ;
	int xorNum = 0;
	for(int i=0;i<data.size();i++)
		xorNum^=data[i];
	int position = getPosition(xorNum);
	for(int i=0;i<data.size();i++)
	{
		if(judge(data[i],position))
			a^=data[i];
		else
			b^=data[i];
	}
	*num1 = a;
	*num2 = b;
 }





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值