题目:
一个整形数组里除了两个数字意外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.
要求时间复杂度是On,空间复杂度为O1
这个是上一篇 2016阿里巴巴java笔试题 的增强版...
还是使用异或,异或到了最后得到结果是怎么样的呢?
其余的数字都互相异或变成了0,所以最后的结果就是这2个不相同的数字的异或结果.
就假定要找的两个数字为数字A和数字B
那么怎么分别得到这2个数字呢?
异或:1^1=0,1^0=1
就看最后异或的结果:他是一个二进制数,那么出现1的地方肯定就是A与B的二进制不相同的地方.
那么就异或的结果中,第一次出现1的时候就说明此时A与B中较大的那个当前位上为1,较小的那个为0.
根据这个,就把所有的数字分为2组:当前位为1的,当前位为0的.
那么原先的一组数据被分为了2组,A,B又分别位于不同的组,那只要分别异或就行了..
例子:
比如说1,1,2,2,3,4,5,5
最后异或的结果就是3^4=1110
根据倒数第4位上是否为1,将原先的数组分为2组:
1,1,2,2,3
4,5,5
这样分别异或,第一组得到3,第二组得到4,完成
代码:
public int[] find(int[] array) { // 异或所有,得到总异或的结果 int result = array[0]; for (int i = 1; i < array.length; i++) { result ^= array[i]; } // 求出倒数第几位为第一个1 // 这里count记录的是倒数第几-1 int count = -1; while (result != 0) { result = result >>> 1; count++; } // 分为两种情况来异或 int target1 = 0; int target2 = 0; for (int i = 0; i < array.length; i++) { if (((array[i] >>> count) & 1) == 1) { target1 ^= array[i]; } else { target2 ^= array[i]; } } return new int[] { target1, target2 }; }