n个数中有且仅有一个数出现了奇数次
来源:互联网 发布:图片比较算法 编辑:程序博客网 时间:2024/05/23 23:48
很有意思奥:
有一组数字,从1到n,中减少了一个数,顺序也被打乱,放在一个n-1的数组里
请找出丢失的数字,最好能有程序,最好算法比较快
BTW1: 有很多种方法的哦,据说O(n)的方法就不止一种
BTW2: 扩展问题,如果丢失了2个数字呢?
BTW3: 一定要小心不要溢出,嗯,面试者有时候不会提醒你的
BTW4: 最好不要多申请n多空间
Update 一个很相近的题目:1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?
题目 :
给你n个数,其中有且仅有一个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那一个数。
给你n个数,其中有且仅有两个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那两个数。
给你n个数,其中有且仅有两个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那两个数。
--------------------------------------------------------------------------------
现在这里给出一些解答:
第一题: 看到题目的第一反应就是把这个n-1个数字加起来,然后和1+2+3..+n的和进行比较,那个差值就是迷失的数字。但是这个方法正是BTW3里面提到的不要溢出:)所以有一定的风险,还是不采用,还有人说用一个个+-来判断,可以是可以但是代码写起来也比较难看(个人感觉),还是异或操作符来的最合适一些。 我们知道1^1=0;2^2=0;n^n=0;k^0=k;所以如果我们把这n-1个数字异或起来,再来异或一下1,2,..n。那么最终的答案肯定是迷失数字k^(1^1)^(2^2)...^(n^n)。也就是K了。我们很容易地写下来了函数:
view plaincopy to clipboardprint?
// in case find one missing number, here size is 1 less than the range n
int find_missing_number1 (int a[], int size)
{
int number=0;
for (int i=0;i<size;i++)
number ^= ((i+1)^a[i]);
number ^= (size+1);
return number;
}
// in case find one missing number, here size is 1 less than the range n
int find_missing_number1 (int a[], int size)
{
int number=0;
for (int i=0;i<size;i++)
number ^= ((i+1)^a[i]);
number ^= (size+1);
return number;
}
// in case find one missing number, here size is 1 less than the range n
int find_missing_number1 (int a[], int size)
{
int number=0;
for (int i=0;i<size;i++)
number ^= ((i+1)^a[i]);
number ^= (size+1);
return number;
}
// in case find one missing number, here size is 1 less than the range n
int find_missing_number1 (int a[], int size)
{
int number=0;
for (int i=0;i<size;i++)
number ^= ((i+1)^a[i]);
number ^= (size+1);
return number;
}
第二个问题来的更复杂一些,如果有两个数字迷失怎么办?还是方法一的方法,但是需要衍生一下。假定我们迷失的数字是S1,S2那么我们全部异或之后得到的就是S1^S2只有的值。分析一下就可以知道,S1!=S2,也就是说S1^S2!=0; 这样也就是说S1^S2的这个值有二进制位有一位是1,那么我们就可以把这些所有的数字分成2组,一组这个二进制位是1,另一个这个二进制位是0的来重新做异或。这样就可以吧其中一个S1求出来了,那再S1^(S1^S2)一下,S2也就得到了。类似地,我们写下了如下的代码:
view plaincopy to clipboardprint?
// in case find two missing numbers, here size is 2 less than the range n
void find_missing_number2 (int a[], int size, int& miss1, int& miss2)
{
miss1 = 0;
miss2 = 0;
int number=0;
for (int i=0;i<size;i++)
number ^= ((i+1)^a[i]);
number ^= (size+1);
number ^= (size+2);
// now number will be miss1^miss2
// find the binary 1 in number
int k = number - (number&(number-1));
for (int i=0;i<size;i++)
{
if ( (i+1)&k )
miss1 ^= (i+1);
if ( a[i]&k )
miss1 ^= a[i];
}
if ( (size+1) & k )
miss1 ^= size+1;
if ( (size+2) & k )
miss1 ^= size+2;
miss2 = number ^ miss1;
}
// in case find two missing numbers, here size is 2 less than the range n
void find_missing_number2 (int a[], int size, int& miss1, int& miss2)
{
miss1 = 0;
miss2 = 0;
int number=0;
for (int i=0;i<size;i++)
number ^= ((i+1)^a[i]);
number ^= (size+1);
number ^= (size+2);
// now number will be miss1^miss2
// find the binary 1 in number
int k = number - (number&(number-1));
for (int i=0;i<size;i++)
{
if ( (i+1)&k )
miss1 ^= (i+1);
if ( a[i]&k )
miss1 ^= a[i];
}
if ( (size+1) & k )
miss1 ^= size+1;
if ( (size+2) & k )
miss1 ^= size+2;
miss2 = number ^ miss1;
}
// in case find two missing numbers, here size is 2 less than the range n
void find_missing_number2 (int a[], int size, int& miss1, int& miss2)
{
miss1 = 0;
miss2 = 0;
int number=0;
for (int i=0;i<size;i++)
number ^= ((i+1)^a[i]);
number ^= (size+1);
number ^= (size+2);
// now number will be miss1^miss2
// find the binary 1 in number
int k = number - (number&(number-1));
for (int i=0;i<size;i++)
{
if ( (i+1)&k )
miss1 ^= (i+1);
if ( a[i]&k )
miss1 ^= a[i];
}
if ( (size+1) & k )
miss1 ^= size+1;
if ( (size+2) & k )
miss1 ^= size+2;
miss2 = number ^ miss1;
}
// in case find two missing numbers, here size is 2 less than the range n
void find_missing_number2 (int a[], int size, int& miss1, int& miss2)
{
miss1 = 0;
miss2 = 0;
int number=0;
for (int i=0;i<size;i++)
number ^= ((i+1)^a[i]);
number ^= (size+1);
number ^= (size+2);
// now number will be miss1^miss2
// find the binary 1 in number
int k = number - (number&(number-1));
for (int i=0;i<size;i++)
{
if ( (i+1)&k )
miss1 ^= (i+1);
if ( a[i]&k )
miss1 ^= a[i];
}
if ( (size+1) & k )
miss1 ^= size+1;
if ( (size+2) & k )
miss1 ^= size+2;
miss2 = number ^ miss1;
}
还找了个test case 测试了一把:
view plaincopy to clipboardprint?
int _tmain(int argc, _TCHAR* argv[])
{
int a[] = { 1,2,4,5,9,7,8,10,3 };
int b[] = { 1,2,4,5,9,7,6,11,3,10 };
int s1,s2;
int k = find_missing_number1(a,sizeof(a)/sizeof(a[0]));
find_missing_number2(b,sizeof(b)/sizeof(b[0]),s1,s2);
std::cout<<"missing number 1 is "<<k<<std::endl;
std::cout<<"missing number 2 is "<<s1 << " and "<<s2<<std::endl;
system("pause");
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[] = { 1,2,4,5,9,7,8,10,3 };
int b[] = { 1,2,4,5,9,7,6,11,3,10 };
int s1,s2;
int k = find_missing_number1(a,sizeof(a)/sizeof(a[0]));
find_missing_number2(b,sizeof(b)/sizeof(b[0]),s1,s2);
std::cout<<"missing number 1 is "<<k<<std::endl;
std::cout<<"missing number 2 is "<<s1 << " and "<<s2<<std::endl;
system("pause");
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[] = { 1,2,4,5,9,7,8,10,3 };
int b[] = { 1,2,4,5,9,7,6,11,3,10 };
int s1,s2;
int k = find_missing_number1(a,sizeof(a)/sizeof(a[0]));
find_missing_number2(b,sizeof(b)/sizeof(b[0]),s1,s2);
std::cout<<"missing number 1 is "<<k<<std::endl;
std::cout<<"missing number 2 is "<<s1 << " and "<<s2<<std::endl;
system("pause");
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[] = { 1,2,4,5,9,7,8,10,3 };
int b[] = { 1,2,4,5,9,7,6,11,3,10 };
int s1,s2;
int k = find_missing_number1(a,sizeof(a)/sizeof(a[0]));
find_missing_number2(b,sizeof(b)/sizeof(b[0]),s1,s2);
std::cout<<"missing number 1 is "<<k<<std::endl;
std::cout<<"missing number 2 is "<<s1 << " and "<<s2<<std::endl;
system("pause");
return 0;
}
看起来两个函数运行的结论是正确的。
后面的问题,Update确实如上所说的,非常类似,把这些个数字和1-1000异或就得到了答案了。奇数偶数的其实问题的第一二小题分别和迷失一个数字和两个数字对应,想法完全一致,这里不做展开了。
本文出自 51CTO.COM技术博客
- n个数中有且仅有一个数出现了奇数次
- 【算法题】找出且仅有的出现了奇数次的一个数
- 在N个数中找出出现奇数次的数
- 218 N个数出现了偶数次,2个数出现了奇数次,找出这两个数
- 一个数组存放了2n+1个整数,其中有n个数出现了2次,1个数出现了1次,找出出现1次的数是多少?
- 趣题:n为奇数时,正n边形的三角形剖分内有且仅有一个锐角三角形
- 找一个数组中出现奇数次的那个数
- 有N个数,其中2个数出现了奇数次(这两个数不相等),其他数都出现偶数次,问用O(1)的空间复杂度,找出这两个数,不需要知道具体位置,只需要知道这两个值。
- 给出N个正整数,其中只有一个数出现了奇数次,其余的数都出现偶数次。求那个出现了奇数次的数。1<=N<=1000,N肯定是奇数。所有出现的整数都不超过1000。
- 长度为n的数组,有一个数m重复出现了n/2+1次,找出这个数
- 在一个大数组中有且仅有两个数相同,怎样尽快找出这两个数(未完成)
- 在一个大数组中有且仅有两个数相同,怎样尽快找出这两个数
- 【面试真题】给定长度为n的数组,内部有n-2个整数出现了偶数次,和2个只出现奇数次的整数,找到这两个数
- 寻找一个数组中出现次数为奇数次的一个数
- 有一个数组,某些数字出现了N次,只有一个出现了M次,求出该数字
- 趣题:寻找出现了奇数次的数
- 寻找出现了奇数次的数 ---线性时间常数空间
- 现在有N个数字,其中只有一个数字出现的次数是奇数次,如何找到这个数字?
- The Loopback Root Filesystem HOWTO
- Delta3D学习之App类
- 远程登录不上linux服务器
- 条款18:让接口容易被正确使用,不易被误用
- 插入多行数据到数据库-SQL
- n个数中有且仅有一个数出现了奇数次
- SQL Server2005四个排序函数简介
- Linux 下的特殊檔案系統
- C#之DateTime类
- Mysql分布事务的探索
- PHP实现的某SNS手机游戏的简单外挂
- linux图形界面层次关系总结
- INSERT...SELECT
- 老子