1.题目
2.思路
首先看数据大小10的5次方,题目要求时间复杂度O(n),空间复杂度O(1)。如果是哈希表,显然不符合空间复杂度,所以就向位运算方面思考。
假如题目中只有一个数出现了1次,其余都出现了2次,是不是直接就可以遍历所有的数,用一次异或,就可以得到这个数字了。(或者借用剑指 Offer 56 - II. 数组中数字出现的次数 II的思路,用与操作,求和然后%2是否等于0.)
异或:2 ^ 2 ^ 3 = 3。这是前提。
第一步还是得计算所有的数字的异或结果得到a ^ b.
第二步是想办法把a 和 b , 分成两组,分别进行异或就可以得到a 和 b。
那么问题来了,如何分组?假如数字是[4,1,4,6]
第一次异或得到1 异或 6 = 7 (111)
然后获取最低位的1是 第1位,那么根据这个第1位是否为1,来划分成两个组,一个组里肯定有1.一个组里肯定有6。然后每个组里的数字分别进行异或就可以得到1 和 6.
class Solution {
public int[] singleNumbers(int[] nums) {
int n = nums.length;
int temp = 0; //记录a 异或 b 的结果。
for(int i = 0 ; i < n ; i++)
temp ^= nums[i];
// 分组两组异或,每一组可以得到一个数
int g1 = 0, g2 = 0;
int cnt = 0; // 根据第i位低位不为0的位置分割成两组数字。
for(int i = 0; i < 32 ; i++){
int t = (temp >> i & 1);
if(t == 1){
cnt = i ;
break;
}
}
for(int i = 0; i < n; i++){
if((nums[i] >> cnt & 1) == 1)
g1 ^= nums[i];
else
g2 ^= nums[i];
}
return new int[]{g1, g2};
}
}
3.结果
4.总结
问题由浅入深,循序渐进。
先思考只有一个数出现次数为1,其余都出现两次的情况。
紧接着问题关键是要分成两组,分别进行异或操作才可以。
分组的关键在于如何把这两个不同的数分开,想一想这两个数的不同点是啥。