题目:http://code.bupt.edu.cn/problem/p/84/
Given an array with N integers where all elements appear three times except for one. Find out the one which appears only once.
N(1≤N≤10^5) All elements are ranged in [0,2^63−1] ;
好吧。以前看过每个数都出现两次,只有一个出现一次,找这个数的题目。这个还真新颖。。。
数据卡的O(nlogn)一丁点就不行,甚至O(N*64)都不行。。。无语了。。。在quora上看到有人讲这个题,大开眼界,记录一下。
主要意思就是用xor(a XOR a = 0)
先把代码贴上
one = two = 0; for(i = 0; i < n; ++i) { scanf("%lld", &a); two |= one&a; one ^= a; del = ~(one&two); one &= del; two &= del; } printf("%lld ", one);
定义:
one:表示只出现过一次的数
two:表示出现过两次的数
del:用来删掉出现三次的数
有如下几种情况:
1、出现一个新的a,通过XOR,放入one中
2、a出现第二次,one中原来有a,one&a就将a放入two中。
3、a出现第三次,要把a从one和two中删掉。
对于下三行代码
del = ~(one&two); one &= del; two &= del;
可以看出其目的是将从one和two中二进制中相同位都为1的位置变为0。
假设现在有4个数(a b a a),走一遍过程。
1# a放到one中,two依然没有数
2# two只有a,one放入b
3# two中依然只有a,one中不再有a(因为被XOR掉了)
4# two中依然有a,one里也存有a,则将one和two二进制中相同位都为1的位置删掉,即删掉a。
最后one里剩下的为b,two里面为0;
ps:one里有a,two里有a指的是a的二进制。