第三十三题 输出容器中3个不同的数
来源:互联网 发布:淘宝网电子琴 编辑:程序博客网 时间:2024/06/06 09:57
题目:一个数组中有三个数字a、b、c只出现一次,其他数字都出现了两次。请找出三个只出现一次的数字。
思路:如果我们把数组中所有数字都异或起来,那最终的结果(记为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三个数字的标准。这三个数字中,只有一个数字满足这个标准,而另外两个数字不满足。一旦这个满足标准数字找出来之后,另外两个数字也就可以找出来了。
#include <iostream>#include <vector>using namespace std;//得到输入数据的只有最后一个1的数int lastBitOf1(int number){return number & ~(number - 1);}void getTwoUnique(vector<int>::iterator begin, vector<int>::iterator end, vector<int>& unique);void getThreeUnique(vector<int>& numbers, vector<int>& unique){if(numbers.size() < 3)return;int index = 0;vector<int>::iterator iter = numbers.begin();//所有数异或过后的结果保存在index中for(; iter != numbers.end(); ++iter)index ^= *iter;//将index分别与所有的数异或得到flagint flags = 0;for(iter = numbers.begin(); iter != numbers.end(); ++iter)flags ^= lastBitOf1(index ^ *iter);flags = lastBitOf1(flags);//此时flag必然不为0,,可以通过flag推出与flag同样位置为1的那个不同的数int first = 0;for(iter = numbers.begin(); iter != numbers.end(); ++iter){if(lastBitOf1(*iter ^ index) == flags)first ^= *iter;}unique.push_back(first);for(iter = numbers.begin(); iter != numbers.end(); ++iter){if(*iter == first){swap(*iter, *(numbers.end() - 1));break;}}getTwoUnique(numbers.begin(), numbers.end() - 1, unique);}//处理只有2个数不同时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);}int main(){vector<int> vec1;vector<int> vec2;vec1.push_back(1);vec1.push_back(3);vec1.push_back(4);vec1.push_back(2);vec1.push_back(3);vec1.push_back(1);vec1.push_back(4);vec1.push_back(5);vec1.push_back(7);getThreeUnique(vec1,vec2);for (auto it=vec2.begin();it!=vec2.end();++it){cout<<*it<<endl;}return 0;}
- 第三十三题 输出容器中3个不同的数
- 输出3个数字位完全不同的完全平方数
- 将奇偶数分别输出到 不同的文件中
- 输出两字符串中第二个字符串的不同部分
- 一个数组中找出2个不同的数
- 求二进制序列中1的个数及奇偶序列+输出整数的每一位+两个数中多少个bit位不同
- 找出N个浮点数中最大的k个不同的浮点数
- OJ刷题之《输出不同进制的数》
- 从1-49选6个不同的数,输出5组(一)
- 从1-49选6个不同的数,输出5组(二)有错?
- 输出双精度数的不同值
- C-SCAUoj 输出不同的数
- [迅雷笔试题]从1....n中随机输出m个不重复的数
- java第三周--(输出任意数之间的所有完数;3位数的任意整数,输出其降序数)
- 剑指offer第三十三题【两个链表的第一个公共结点】c++实现
- 随机生成10个不同的数
- 写出10个随机不同的数
- UVALive7045 多少个不同的数
- hdu 4648
- Console类——方便向控制台读取与写入内容
- 如何batch跑matlab程序
- leetcode学习笔记:Trapping Rain Water
- java算法之下压栈来动态调整数组大小
- 第三十三题 输出容器中3个不同的数
- uva 11375 - Matches(递推)
- 黑马程序员——银行业务调度系统
- Struts2框架(一)
- 【教程】关于各种USB启动模式的解读 MBR、PBR
- box2d——1.tiles瓦片积木
- Android浏览图片,点击放大至全屏效果
- StringBuffer的用法
- 下一站