一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
这道题是有两个数字只出现一次,另外有个题是只有一个数字出现了一次,其他数字出现两次
,做法是对数组中的数字两两异或,最后的结果就是该出现一次的数字。
对于这道题,出现两次,数组长度肯定为偶数,那么我们可以先将等分为两部分,对每部分中的数字进行两两异或,那么会出现两种情况:
- 当这两个
出现一次
的数字在同一部分中,那么必定有另外一部分的两两异或结果为 0 - 当这两个
出现一次
的数字分别在不同的部分中,那么两部分的两两异或结果就分别是这两个数字
我们需要的第二种情况,因为只有当这两个出现一次
的数字分别在不同的部分中,我们才能分别得出这两个数字,所以应该一直重复1,直至出现2的情况。
但是还有另外一种思想:我们可以让数组中的每一个数异或一下,最后会得到一个结果res
,就是两个出现一次的数字的异或结果这个结果肯定是由两个不同数字异或而来,因此我们找res
二进制中为1的位置i
,因为1一定是由 0,1 异或而来,因此要求两个数中,一定有一个数的二进制中的第i个位置为 1, 一个为 0。
如何找到位置 i
?可用i = res ^ (-res)
因为计算机用补码存取二进制数,而负数的补码为反码+1,举个例子
假如res = 1110 , -res = 0010 , 所以 i = 0010
所以,再异或一遍即可得到答案。
Java实现如下:
// num1,num2分别为长度为1的数组。传出参数
// 将num1[0],num2[0]设置为返回结果
// 0 异或任何数都等于该数
public class Solution {
public void FindNumsAppearOnce(int [] array, int num1[] , int num2[]) {
int res = 0;
for(int each:array) res ^= each;
res &= (-res);
num1[0] = 0;
num2[0] = 0;
for(int each:array){
if((each & res)==0) num1[0] ^= each;
else num2[0] ^= each;
}
}
}
时间复杂度:O(n)
空间复杂度:O(1)