本文来讲两道关于从大数据中找唯一出现一次或两次的数。
题目分别如下
1.给定一个长度为1000001的整数数组,没有排过序,所有整数的范围均在int内,除了其中一个数字出现过1次以外,其余的数字都出现过2次,找出这个唯一出现1次的数字。
因为异或操作有一个性质:相同两个数异或结果为零,零和任何数的异或结果为任何数。即a^a=0,0^a=a,那么所有出现两次的数异或起来得到的结果为零,将这个零再与唯一出现一次的数进行异或,就得到了那个数了,在这里异或操作满足交换律。
所以只需要将这1000001个数字异或起来就得到那个唯一出现1次的数字了。代码如下
int solve(int a[], int n) { int ans = 0; for (int i = 0; i < n; i++) { ans ^= a[i]; } return ans;}
2.给定一个长度为1000001的整数数组,没有排过序,所有整数的范围均在int内,除了其中一个数字出现过2次以外,其余的数字都出现过3次,找出这个唯一出现2次的数字。
这道题就要比上面的题难一点了,首先有一个明显的性质:出现过三次的所有数字加起来一定能被3整除。我们如果把所有数字都写成三进制的形式,即如下
那么将相同次幂的系数都加起来并且对3取余,其结果将和唯一出现过两次的数字的和对3取余一样,假如最终得到的系数为k0,k1,k2,...,km,那么对于其中某个ki,有
我们需要求a_i的值,将上述式子变形得到如下结果
因为k_i是系数,所以k_i∈[0, 2],这里可通过扩展欧几里得算法解方程求出a_i。
还可以通过用逆元公式求a_i,即算出2模3的逆元,得到
即2模3的逆元为2,所以计算a_i的公式如下
得到所有的a_i后,再转化为十进制就是我们要求的x的值了。代码如下
这两道题算是比较经典的面试题,掌握这些思想很重要。