http://zhedahht.blog.163.com/blog/static/25411174201283084246412/

题目:一个数组中有三个数字a、b、c只出现一次,其他数字都出现了两次。请找出三个只出现一次的数字。

分析:在博客http://zhedahht.blog.163.com/blog/static/2541117420071128950682/中我们讨论了如何在一个数组中找出两个只出现一次的数字。在这道题中,如果我们能够找出一个只出现一次的数字,剩下两个只出现一次的数字就很容易找出来了。

如果我们把数组中所有数字都异或起来,那最终的结果(记为x)就是a、b、c三个数字的异或结果(x=a^b^c)。其他出现了两次的数字在异或运算中相互抵消了。

我们可以证明异或的结果x不可能是a、b、c三个互不相同的数字中的任何一个。我们用反证法证明。假设x等于a、b、c中的某一个。比如x等于a,也就是a=a^b^c。因此b^c等于0,即b等于c。这与a、b、c是三个互不相同的三个数相矛盾。

由于x与a、b、c都各不相同,因此x^a、x^b、x^c都不等于0。

我们定义一个函数f(n),它的结果是保留数字n的二进制表示中的最后一位1,而把其他所有位都变成0。比如十进制6表示成二进制是0110,因此f(6)的结果为2(二进制为0010)。f(x^a)、f(x^b)、f(x^c)的结果均不等于0。

接着我们考虑f(x^a)^f(x^b)^f(x^c)的结果。由于对于非0的n,f(n)的结果的二进制表示中只有一个数位是1,因此f(x^a)^f(x^b)^f(x^c)的结果肯定不为0。这是因为对于任意三个非零的数i、j、k,f(i)^f(j)的结果要么为0,要么结果的二进制结果中有两个1。不管是那种情况,f(i)^f(j)都不可能等于f(k),因为f(k)不等于0,并且结果的二进制中只有一位是1。

于是f(x^a)^f(x^b)^f(x^c)的结果的二进制中至少有一位是1。假设最后一位是1的位是第m位。那么x^a、x^b、x^c的结果中,有一个或者三个数字的第m位是1。

接下来我们证明x^a、x^b、x^c的三个结果第m位不可能都是1。还是用反证法证明。如果x^a、x^b、x^c的第m位都是1,那么a、b、c三个数字的第m位和x的第m位都相反,因此a、b、c三个数字的第m位相同。如果a、b、c三个数字的第m位都是0,x=a^b^c结果的第m位是0。由于x和a两个数字的第m位都是0,x^a结果的第m位应该是0。同理可以证明x^b、x^c第m位都是0。这与我们的假设矛盾。如果a、b、c三个数字的第m位都是1,x=a^b^c结果的第m位是1。由于x和a两个数字的第m位都是1,x^a结果的第m位应该是0。同理可以证明x^b、x^c第m位都是0。这还是与我们的假设矛盾。

因此x^a、x^b、x^c三个数字中,只有一个数字的第m位是1。于是我们找到了能够区分a、b、c三个数字的标准。这三个数字中,只有一个数字满足这个标准,而另外两个数字不满足。一旦这个满足标准数字找出来之后,另外两个数字也就可以找出来了。

这种思路的C++代码如下:

void getThreeUnique(vector<int>& numbers, vector<int>& unique)
{if(numbers.size() < 3)return;int xorResult = 0;vector<int>::iterator iter = numbers.begin();for(; iter != numbers.end(); ++iter)xorResult ^= *iter;int flags = 0;for(iter = numbers.begin(); iter != numbers.end(); ++iter)flags ^= lastBitOf1(xorResult ^ *iter);flags = lastBitOf1(flags);// get the first unique numberint first = 0;for(iter = numbers.begin(); iter != numbers.end(); ++iter){if(lastBitOf1(*iter ^ xorResult) == flags)first ^= *iter;}unique.push_back(first);// move the first unique number to the end of arrayfor(iter = numbers.begin(); iter != numbers.end(); ++iter){if(*iter == first){swap(*iter, *(numbers.end() - 1));break;}}// get the second and third unique numbersgetTwoUnique(numbers.begin(), numbers.end() - 1, unique);
}int lastBitOf1(int number)
{return number & ~(number - 1);
}void getTwoUnique(vector<int>::iterator begin, vector<int>::iterator end, vector<int>& unique)
{int xorResult = 0;for(vector<int>::iterator iter = begin; iter != end; ++iter)xorResult ^= *iter;int diff = lastBitOf1(xorResult);int first = 0;int second = 0;for(vector<int>::iterator iter = begin; iter != end; ++iter){if(diff & *iter)first ^= *iter;elsesecond ^= *iter;}unique.push_back(first);unique.push_back(second);
}

数组中三个只出现一次的数字相关推荐

  1. 程序员面试题精选100题(63)-数组中三个只出现一次的数字[算法]

    题目:一个数组中有三个数字a.b.c只出现一次,其他数字都出现了两次.请找出三个只出现一次的数字. 分析:在博客http://zhedahht.blog.163.com/blog/static/254 ...

  2. 算法题:找出整数数组中两个只出现一次的数字

    问题:一个整数数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度为O(n),空间复杂度为O(1). 分析:这是一个很新颖的关于位运算的题目. 首先考虑这 ...

  3. 微策略2011校园招聘笔试题(找出数组中两个只出现一次的数字)

    1.8*8的棋盘上面放着64个不同价值的礼物,每个小的棋盘上面放置一个礼物(礼物的价值大于0),一个人初始位置在棋盘的左上角,每次他只能向下或向右移动一步,并拿走对应棋盘上的礼物,结束位置在棋盘的右下 ...

  4. 找出数组中两个只出现一次的数字

    题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字 通过这道题感觉位运算很强大~这道题利用异或的几个性质:任何数与其本身异或值都为0,异或运算满足交换律. ...

  5. 【算法14】找出数组中两个只出现一次的数字

    [题 目]一个整型数组中除了两个数字外,其他的数字都出现两次.请找出这两个只在数组中出现一次的数字.要求时间复杂度O(n),空间复杂度O(1). [思 路]首先我们考虑一个稍微简单点的情况:如果这个数 ...

  6. 找出数组中两个只出现了一次的数

    原题:给一组数,只有两个数只出现了一次,其他所有数都是成对出现的.怎么找出这两个数. 编写函数实现. 对于一组数中只有一个数只出现一次,其他所有数都是成对出现的,我们采用了对全部数组元素进行异或,经过 ...

  7. 找出数组中第k大和第m大的数字之和

    找出数组中第k大和第m大的数字之和 说明:定义一个函数,接受三个参数getMaxNumber(array,k,m){},找出第k大和第m大的数字之和.重复的数组也需要计算 比如:[1,3,4,5,4, ...

  8. 数组中删数(只删一个)

    Description 在给定的数组中删除一个数 Input 多组测试,每组第一行输入1个整数n(n<20),然后是n个整数 第二行输入1个整数m Output 删除在第一行的n个整数中第一次出 ...

  9. 位运算在一类数组题中的用法 只出现一次的数字I

    文章目录 前言 复习 一:只出现一次的数字I 二:只出现一次的数字II 二:只出现一次的数字III 前言 LeetCode上有几道题特别相似,分别是leetcode 136只出现一次的数(简单),13 ...

最新文章

  1. 连接oracle内存溢出,Linux主机内存溢出导致oracle的SYS用户无法正常登陆
  2. JAVA SE学习day_04:RandomAccessFile
  3. 《图解HTTP》读书笔记(四:HTTP方法)
  4. 数据映射--平衡二叉有序树
  5. 二叉树的应用- 找出倚天屠龙记小说里所有的成语
  6. jdbc连接gp单例模式_JDBC连接备忘单
  7. print函数python_带有结束参数的Python print()函数
  8. C++最普通的定时器功能实现
  9. 添加中文菜单项出现乱码的解决办法
  10. 如何有效使用OpenPower720(上)
  11. 复制当前地址到系统剪贴板
  12. LDA线性判别原理解析<数学推导>
  13. 【Hack The Box】windows练习-- Conceal
  14. 【java】汽车租赁系统_结课作业
  15. 物联网和互联网之间,主要有什么关系?
  16. 拍照时光圈与景深控制
  17. Vue2 Browserslist: caniuse-lite is outdated. Please run: npx browserslist@latest --update-db
  18. 如何给宝宝取一个高雅有内涵的名字
  19. 艾司博讯:在拼多多开店都有什么步骤
  20. 何恺明的ResNet论文,被引量刚刚突破10万大关

热门文章

  1. 加法器 编码器 译码器 显示译码器
  2. 8.23 前端面经总结
  3. 年末最大AI盛典!2020深度学习开发者峰会报名启动
  4. 10万元奖金“智源工业检测赛”激战正酣!高分Baseline合辑带你入门智能制造
  5. 智源“高能对撞粒子分类挑战赛”开启,品鉴宇宙粒子的独特“味道”
  6. Github项目推荐 | OI Wiki:编程竞赛最全知识整合站点
  7. 岗位推荐 | 微软小冰团队招聘数据挖掘/算法工程师实习生
  8. Thymeleaf 语法快速入门
  9. 电音之王 对64bit int 取模
  10. python 中的路径. ./ .. ../和相对路径的写法