博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数组中只出现一次的数字
阅读量:6325 次
发布时间:2019-06-22

本文共 2594 字,大约阅读时间需要 8 分钟。

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

数字都出现两次,则异或肯定为0。

考虑下这个题目的简化版——数组中除一个数字只出现1次外,其它数字都成对出现,要求尽快找出这个数字。根据异或运算的特点,直接异或一次就可以找出这个数字。

现在数组中有两个数字只出现1次,直接异或一次只能得到这两个数字的异或结果,但光从这个结果肯定无法得到这个两个数字。因此我们来分析下简化版中“异或”解法的关键点,这个关键点也相当明显——数组只能有一个数字出现1次

    设题目中这两个只出现1次的数字分别为A和B,如果能将A,B分开到二个数组中,那显然符合“异或”解法的关键点了。因此这个题目的关键点就是将A,B分开到二个数组中。由于A,B肯定是不相等的,因此在二进制上必定有一位是不同的。根据这一位是0还是1可以将A,B分开到A组和B组。而这个数组中其它数字要么就属于A组,要么就属于B组。再对A组和B组分别执行“异或”解法就可以得到A,B了。而要判断A,B在哪一位上不相同,只要根据A异或B的结果就可以知道了,这个结果在二进制上为1的位都说明A,B在这一位上是不相同的。

    比如int a[] = {1, 1, 3, 5, 2, 2}

    整个数组异或的结果为3^5即 0x0011 ^ 0x0101 = 0x0110

    对0x0110,第1位(由低向高,从0开始)就是1。因此整个数组根据第1位是0还是1分成两组。

    a[0] =1  0x0001  第一组

    a[1] =1  0x0001  第一组

    a[2] =3  0x0011  第二组

    a[3] =5  0x0101  第一组

    a[4] =2  0x0010  第二组

    a[5] =2  0x0010  第二组

    第一组有{1, 1, 5},第二组有{3, 2, 3},明显对这二组分别执行“异或”解法就可以得到5和3了。

1 class Solution { 2 public: 3     void FindNumsAppearOnce(vector
data,int* num1,int *num2) { 4 int temp=0; 5 int n=data.size(); 6 if(n<2) return; 7 int i,j; 8 for(i=0;i
>j)&1==1)12 break;13 }14 for(i=0;i
>j)&1==1){16 *num1^=data[i];17 }18 else19 *num2^=data[i];20 }21 }22 };

扩展:数组A中,除了某一个数字x之外,其他数字都出现了三次,而x出现了一次。请给出最快的方法找到x。

我们换一个角度来看,如果数组中没有x,那么数组中所有的数字都出现了3次,在二进制上,每位上1的个数肯定也能被3整除。如{1, 5, 1, 5, 1, 5}从二进制上看有:

1:0001

5:0101

1:0001

5:0101

1:0001

5:0101

二进制第0位上有6个1,第2位上有3个1.第1位和第3位上都是0个1,每一位上的统计结果都可以被3整除。而再对该数组添加任何一个数,如果这个数在二进制的某位上为1都将导致该位上1的个数不能被3整除。因此通过统计二进制上每位1的个数就可以推断出x在该位置上是0还是1了,这样就能计算出x了。

推广一下,所有其他数字出现N(N>=2)次,而一个数字出现1次都可以用这种解法来推导出这个出现1次的数字。

1 // 【白话经典算法系列之十七】数组中只出现一次的数 2 //  by MoreWindows( http://blog.csdn.net/MoreWindows )  3 //  欢迎关注http://weibo.com/morewindows 4 #include 
5 #include
6 int FindNumber(int a[], int n) 7 { 8 int bits[32]; 9 int i, j;10 // 累加数组中所有数字的二进制位11 memset(bits, 0, 32 * sizeof(int));12 for (i = 0; i < n; i++)13 for (j = 0; j < 32; j++)14 bits[j] += ((a[i] >> j) & 1);15 // 如果某位上的结果不能被整除,则肯定目标数字在这一位上为16 int result = 0;17 for (j = 0; j < 32; j++)18 if (bits[j] % 3 != 0)19 result += (1 << j);20 return result;21 }22 int main()23 {24 printf(" 【白话经典算法系列之十七】数组中只出现一次的数\n");25 printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n");26 printf(" -- http://blog.csdn.net/morewindows/article/details/12684497 -- \n\n");27 28 const int MAXN = 10;29 int a[MAXN] = {
2, 3, 1, 2, 3, 4, 1, 2, 3, 1};30 printf("%d\n", FindNumber(a, MAXN));31 return 0;32 }

运行结果如下图所示:

 

 

本文地址:

你可能感兴趣的文章
【初学小骆驼】哈希
查看>>
STS 自动生成 getter 和 setter
查看>>
Docker私有仓库介绍
查看>>
maven项目生成war包
查看>>
更换Ubuntu内核
查看>>
目录与前言-GitHub入门与实践(零)
查看>>
Apriori
查看>>
C# 图片的裁剪,两个图片合成一个图片
查看>>
javaScript 函数
查看>>
设计模式的六大原则
查看>>
Objective-C [01]
查看>>
Windows 8 系列(十):关于AppBar持久显示的相关问题
查看>>
求Sn=a+aa+aaa+aaaa+aaaaa的前5项之和,其中a是一个数字
查看>>
php中单引号和双引号的区别
查看>>
chrome贴吧插件——源代码
查看>>
2018.8.21提高AB组模拟考试
查看>>
Unity3d插件推荐
查看>>
2Sum
查看>>
20165323 实验二 Java面向对象程序设计
查看>>
3.6
查看>>