数组中只出现一次的字符

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

每个测试案例包括两行:

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

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

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

思路:

设a、b仅出现一次。
1.假如数组中只有一个数字出现一次,其他数字均出现两次。我们可以通过异或的性质找到这个数字。因为异或有这样的性质,任何一个数异或自己总是0,0异或任何数都等于任何数本身。所以我们可以遍历数组,挨个异或,最后剩下的就是只出现一次的数字,其他数字都被抵消了。
2.现在我们的目的是将只出现一次的两个数分开,分别放到两个集合中,这样便可以利用1的结论来做。
3.我们仍然从头异或到尾,得到的结果为该数组中只出现一次的两个数字的异或值(a^b),结果必然不是0,我们可以从右向左找到a^b中第一位为1的数(二进制),表示a和b第一个不同的位,我们按照该位是否为1将数组分成两部分,那么每个部分均只有一个数字出现一次。

代码:

/*
数组中只出现一次的数字
by Rowandjj
2014/8/14
*/
#include<stdio.h>
#include<stdlib.h>
/**
 *找到数字xorVal的二进制中第一个值为1的位
 *
 */
int FirstBitIs1(int xorVal)
{
	int index = 0;
	while(((xorVal&1)==0) && (index < 8*sizeof(int)))//不能越界,注意运算符优先级,多加几个括号
	{
		index++;
		xorVal = xorVal>>1;
	}
	return index;
}
/**
 *判断data中第index位(二进制)是否为1
 */
bool isBit1(int data,int index)
{
	data = data>>index;
	return data&1;
}
/**
 * data 目标数组
 * len  数组长度
 * num1 一个只出现一次的数字
 * num2 另一个只出现一次的数字
 */
bool FindNumberAppearOnce(int data[],int len,int *num1,int *num2)
{
	if(data == NULL || len < 2)
	{
		return false;
	}
	int i;
	int xorVal = 0;
	for(i = 0; i < len; i++)
	{
		xorVal ^= data[i];
	}

	int indexOf1 = FirstBitIs1(xorVal);
	*num1 = *num2 = 0;//一定要赋值为0
	for(i = 0; i < len; i++)
	{
		if(isBit1(data[i],indexOf1))
		{
			*num1 ^= data[i];
		}else
		{
			*num2 ^= data[i];
		}
	}
	return true;
}
int main()
{
	int n;
	while(scanf("%d",&n) != EOF)
	{
		if(n <= 1)
		{
			continue;
		}
		int *arr = (int*)malloc(sizeof(int)*n);
		if(!arr)
		{
			exit(-1);
		}
		int i;
		for(i = 0; i < n; i++)
		{
			scanf("%d",arr+i);
		}
		int num1,num2;
		if(FindNumberAppearOnce(arr,n,&num1,&num2))
		{
			if(num1 < num2)
			{
				printf("%d %d\n",num1,num2);
			}else
			{
				printf("%d %d\n",num2,num1);
			}
		}
		free(arr);
	}
	return 0;
}

上面代码可以再优化下,有这样的一个性质:a&(-a)将会把a的二进制形式中最右边的1保留,其他位置0.比如10(1010)&-10(0110) = 0010。

代码:

/*
数组中只出现一次的数字
*/
#include<stdio.h>
#include<stdlib.h>
bool FindFirstAppearOnceNum(int data[],int len,int *num1,int *num2)
{
	if(data == NULL || len <= 1)
	{
		return false;
	}
	int i;
	int xorVal = 0;
	for(i = 0; i < len; i++)
	{
		xorVal ^= data[i];
	}
	*num1 = *num2 = 0;//一定要赋值为0
	int temp = xorVal & (-xorVal);//结果:xorVal中最右边的1被保留其他位为0
	for(i = 0; i < len; i++)//遍历数组,将数组分成两部分,每一部分只有一个数字出现一次
	{
		if(data[i] & temp)//temp中某一位为1,其他位为0,再与上data[i]就可以将两个只出现一次的数字分开
		{
			*num1 ^= data[i];
		}else
		{
			*num2 ^= data[i];
		}
	}
	return true;
}
int main()
{
	int n;
	while(scanf("%d",&n) != EOF)
	{
		if(n <= 1)
		{
			continue;
		}
		int *arr = (int*)malloc(sizeof(int)*n);
		if(!arr)
		{
			exit(-1);
		}
		int i;
		for(i = 0; i < n; i++)
		{
			scanf("%d",arr+i);
		}
		int num1,num2;
		if(FindFirstAppearOnceNum(arr,n,&num1,&num2))
		{
			if(num1 < num2)
			{
				printf("%d %d\n",num1,num2);
			}else
			{
				printf("%d %d\n",num2,num1);
			}
		}
		free(arr);
	}
	return 0;
}

数组中只出现一次的字符

时间: 2024-10-06 02:53:40

数组中只出现一次的字符的相关文章

【白话经典算法系列之十七】 数组中只出现一次的数 其他三次

本文地址:http://blog.csdn.net/morewindows/article/details/12684497转载请标明出处,谢谢. 欢迎关注微博:http://weibo.com/MoreWindows 首先看看题目要求: 数组A中,除了某一个数字x之外,其他数字都出现了三次,而x出现了一次.请给出最快的方法找到x. 这个题目非常有意思,在本人博客中有<位操作基础篇之位操作全面总结>这篇文章介绍了使用位操作的异或来解决——数组中其他数字出现二次,而x出现一次,找出x.有<

数组中只出现一次的数字(剑指offer)思维有点巧

数组中只出现一次的数字 参与人数:1144时间限制:1秒空间限制:32768K 通过比例:21.75% 最佳记录:0 ms|0K(来自  牛客563536号) 题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 题目链接:http://www.nowcoder.com/practice/e02fdb54d7524710a7d664d082bb7811?rp=2&ru=/ta/coding-interviews&qru=/ta/coding

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

数组中只出现一次的数字 题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 思路 先考虑一个数组里只有一个数出现一次,其他两个数都出现两次的情况:一个数跟自己异或后为0,一个数组里只有一个数出现一次其他两次,挨个异或后最后得到的结果就是只出现一次的那个数. 我们把这个数组分为两部分,每部分只有一个数只出现一次:我们分的时候,把所有数都异或后,得到的结果肯定不为0,其实是那两个只出现一次的不同的数的异或,我们从低位到高危找到第一个不为0的那位,异

编程算法 - 数组中只出现一次的数字 代码(C)

数组中只出现一次的数字 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 一个整型数组里除了两个数字以外, 其他的数字都出现了两次. 请写程序找出这两个只出现一次的数字. 如果从头到尾依次异或数组中的每一个数字, 那么最终的结果刚好是那个只出现一次的数字. 根据结果数组二进制某一位为1, 以此分组, 为1的一组, 为0的一组, 再重新进行异或. 最后得出两个结果. 时间复杂度O(n). 代码: /* * main.cpp * * Create

剑指offer系列源码-数组中只出现一次的数字

题目1351:数组中只出现一次的数字 时间限制:1 秒内存限制:32 兆特殊判题:否提交:2582解决:758 题目描述: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 输入: 每个测试案例包括两行: 第一行包含一个整数n,表示数组大小.2<=n <= 10^6. 第二行包含n个整数,表示数组元素,元素均为int. 输出: 对应每个测试案例,输出数组中只出现一次的两个数.输出的数字从小到大的顺序. 样例输入: 8 2 4 3 6 3 2 5 5

【01】数组中只出现一次的数字

其他两次,一个一次/其他三次,一个一次/其他两次,两个一次 ============================================ 任何一个数字异或他自己都得零. 注意异或运算的初始化变量为0,因为0异或任何数字都得那个数字自身. Single Number 1.一个整型数组中除了一个数字之外,其他数字都出现了两次 ,找出这个出现一次的数字. 解法一,异或是重复的消失,剩下的就是要找的数字. C++ Code 12345678910111213   int singleNumb

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

转载请注明出处:http://blog.csdn.net/ns_code/article/details/27649027 题目描述: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 输入: 每个测试案例包括两行: 第一行包含一个整数n,表示数组大小.2<=n <= 10^6. 第二行包含n个整数,表示数组元素,元素均为int. 输出: 对应每个测试案例,输出数组中只出现一次的两个数.输出的数字从小到大的顺序. 样例输入: 8 2 4 3 6 3

[剑指Offer]40.数组中只出现一次的数字

题目 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 思路 我们直到异或的性质: 任何一个数字异或他自己都等于0. 所以说我们如果从头到尾依次异或每一个数字,那么最终的结果刚好只出现一次的数字,因为成对出现的两次的数字全部在异或中抵消了. 这道题中有两个数字只出现一次.这样的话我们得到的结果就是这两个数字的异或结果.因此我们想办法把原数组分成两个子数组,使得每个子数组包含一个只出现一次的数字.这样我们就可以对这两个子数组分别异或,就能得到两个只出现一

【4】数组中只出现一次的数字

题目:输入一个整型数组,数组里除了两个数出现一次之外,其它所有数字出现的次数都是2次,求这两个数字.要求时间复杂度为O(n),空间复杂度为O(1) 1 题目要求时间复杂度为O(n)并且空间复杂度为O(1).这个时候朴素的方法利用数字来记录出现次数的方案都是不行的. 2 根据题目的特点,只有两个数出现一次,其它的所有数据都是出现2次.如果这两个数是a和b,那么对这个数组异或的结果就是a^b.现在我们就是要考虑怎么把数组分成两部分,一部分含有a,一部分含有b,则每部分异或的结果即为两个数a和b的值