【剑指offer】数组中只出现一次的数字(1)

转载请注明出处:http://blog.csdn.net/ns_code/article/details/27649027

题目描述:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
输入:

每个测试案例包括两行:

第一行包含一个整数n,表示数组大小。2<=n <= 10^6。

第二行包含n个整数,表示数组元素,元素均为int。

输出:
对应每个测试案例,输出数组中只出现一次的两个数。输出的数字从小到大的顺序。
样例输入:
8
2 4 3 6 3 2 5 5
样例输出:
4 6

思路:上篇博文中已经了解到异或去重的原理,而且知道如果只有一个只出现一次的数字的求法,但这里是有两个只出现一次的数字,我们便要想办法把他分为两个子数组,每个子数组中包含一个只出现一次的数字,其他的数字都出现了两次。剑指offer上的思路很巧妙,依然从头到尾异或所有的数字,这样得到的结果实际上就是两个只出现了一次的数字异或的结果,我们在异或后的结果中找出其二进制中最右边为1的位,该位既然为1,说明异或的两个数字对应的该位肯定不同,必定一个为1,一个为0,因此我们可以考虑根据此位是否为1来划分这两个子数组,这样两个只出现一次的数字就分开了,但我们还要保证出现两次的数字都分到同一个子数组中,肯定不能两个重复的数字分在两个不同的子数组中,这样得到的结果是不对的,很明显,相同的数字相同的位上的值是相同的,要么都为1,要么都为0,因此我们同样可以通过判断该位是否为1来将这些出现两次的数字划分到同一个子数组中,该位如果为1,就分到一个子数组中,如果为0,就分到另一个子数组中。这样就能保证每个子数组中只有一个出现一次的数字,其他的数字都出现两次,分别全部异或即可得到这两个只出现一次的数字。时间复杂度为O(n)。

另外,所有元素异或后,在找出最右边为1的时,我用的比剑指offer上更简洁的代码,主要用到了下面的结论:

对于一个数字X,X&(-X)之后得到的数字,是把X中最右边的1保留下来,其他位全部为0。注意,这里的-X是X的相反数,-X=~X+1,这里的~X意思是对X所有位取反,不要将二者弄混了。

下面是AC的代码:

#include<stdio.h>
#include<stdbool.h>

/*
返回num的最低位的1,其他各位都为0
*/
int FindFirstBit1(int num)
{
	//二者与后得到的数,将num最右边的1保留下来,其他位的全部置为了0
	return num & (-num);
}

/*
判断data中特定的位是否为1,
这里的要判断的特定的位由res确定,
res中只有一位为1,其他位均为0,由FindFirstBit1函数返回,
而data中要判断的位便是res中这唯一的1所在的位
*/
bool IsBit1(int data,int res)
{
	return ((data&res)==0) ? false:true;
}

void FindNumsAppearOnce(int *arr,int len,int *num1,int *num2)
{
	if(arr==NULL || len<2)
		return;

	int i;
	int AllXOR = 0;
	//全部异或
	for(i=0;i<len;i++)
		AllXOR ^= arr[i];

	int res = FindFirstBit1(AllXOR);

	*num1 = *num2 = 0;
	for(i=0;i<len;i++)
	{
		if(IsBit1(arr[i],res))
			*num1 ^= arr[i];
		else
			*num2 ^= arr[i];
	}
}

int main()
{
	static int arr[1000000];
	int n;
	while(scanf("%d",&n) != EOF)
	{
		int i;
		for(i=0;i<n;i++)
			scanf("%d",arr+i);

		int num1,num2;
		FindNumsAppearOnce(arr,n,&num1,&num2);
		if(num1 < num2)
			printf("%d %d\n",num1,num2);
		else
			printf("%d %d\n",num2,num1);
	}
	return 0;
}

/**************************************************************

    Problem: 1351

    User: mmc_maodun

    Language: C

    Result: Accepted

    Time:780 ms

    Memory:4820 kb

****************************************************************/

【剑指offer】数组中只出现一次的数字(1),布布扣,bubuko.com

时间: 2024-10-20 20:02:39

【剑指offer】数组中只出现一次的数字(1)的相关文章

剑指Offer40:数组中只出现一次的数字(Java)

参考hezhiyao的博客 https://www.cnblogs.com/hezhiyao/p/7539024.html 参考qmss的博客 https://www.jianshu.com/p/c308e4a1e19f 参考Raise的博客 https://blog.csdn.net/linraise/article/details/9425319 思路分析: 利用两个相同的数异或为0的性质,两个不为零且不同的数异或运算结果的二进制形式一定有1的性质 解题步骤: 1. 把数组从左到右全部异或运

剑指Offer--040-数组中只出现一次的数字

链接 牛客OJ:数组中只出现一次的数字 九度OJ:http://ac.jobdu.com/problem.php?pid=1351 GitHub代码: 040-数组中只出现一次的数字 CSDN题解:剑指Offer–040-数组中只出现一次的数字 牛客OJ 九度OJ CSDN题解 GitHub代码 040-数组中只出现一次的数字 1351-数组中只出现一次的数字 剑指Offer–040-数组中只出现一次的数字 040-数组中只出现一次的数字 题意 题目描述 一个整型数组里除了两个数字之外,其他的数

剑指offer 数组中的逆序对

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000000007 输入描述: 题目保证输入的数组中没有的相同的数字 数据范围: 对于%50的数据,size<=10^4 对于%75的数据,size<=10^5 对于%100的数据,size<=2*10^5 示例1 输入 1,2,3,4,5,6,7,0 输出 7 思路:归并排序的思路.具体参考剑指

剑指 Offer —— 数组中重复的数字

数组中的重复数字 题目描述 牛课网链接 长度为 n 的数组里,所有数字都在 0 到 n-1 的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 7 的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字 2 或者 3.(牛课网这里弄成「那么对应的输出是第一个重复的数字 2」了) A 简单实现思路 借助外部数组 b,原数组中的数字记为外部数组的下标,外部数组的值来存储这个数字出现的次数.原数组中

剑指offer——数组中出现次数超过一半的数字(c++)

题目描述数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如果不存在则输出0. 思路一遍历数组是保存两个值:一个是数字中的一个数字,另一个是次数.当遍历到下一个数字的时候,如果下一个数字和之前保存的数字相等,则次数加1:如果不同,则次数减1:如果次数为零,那么我们需要保存下一个数字,并把次数设置为1.由于我们要找的数字出现的次数比其他所有数字出现的次数之和还

剑指offer——数组中的逆序对

数组中的逆序对 **(不会)数据结构--小和问题 逆序对问题 原文地址:https://www.cnblogs.com/SkyeAngel/p/8978980.html

python剑指offer数组中出现次数超过一半的数字

题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如果不存在则输出0. 思路: 两种思路.第一种思路,出现次数超过一半的数字,不管如何,必然这个数字位于数组中间的位置,因此可以采用类似于快排的划分的方法,找到位于数组中间的位置的数字,然后在顺序检索是否这个数字出现次数超过一半.第二种思路根据数组的特点,出现次数超过一半的数,他出现的次数比其他数字出

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

//除了两个数字 A和B不相等 所以异或完以后的C C为1的某一位上 A和B在这一位上肯定是相异的 //不然不会异或为1 所以按这一位上为零或者为1来把数组分为两个 //因为同一个数是不可能被分到两个组的 //简化为只有一个数字外 其余都出现两次的这个问题 class Solution { public: int find(int num) { int result=0; while(((num&1)==0)&&result<32) { num=num>>1; +

剑指offer 数组中出现超过一半的数字

class Solution { public: int MoreThanHalfNum_Solution(vector<int> numbers) { if(numbers.empty()){ return 0; } if(numbers.size() == 1){ return numbers[0]; } int len = (int)numbers.size(); float target = len/2.0; map<int, int> m; for(int num: nu