题目链接
思路:异或+分类
这个题目是只出现一次的数字,但是有两个只出现一次的数字。
先从简单一点的题目出发,如果只有一个出现一次的数字,方法是只要全部异或一遍,得到的就是答案。
现在有两个数字,全部异或一遍,得到的数字是两个答案异或的结果。
那么我们需要将这个问题简化一下,能不能把这个数组分为两个数组,并且要将这两个答案分到不同的数组中。
这才是问题的核心。
我们想想这两个答案有什么不同的特征呢,异或一定不为0。
这就是突破点,异或一定不为0,那么二进制表示一定存在至少一位不相同。
那么我们就可以找到某一个这两个答案二进制不同的位,进行分类,那么就可以保证这两个答案一定被分在不同的数组,理论存在,开始代码。
代码:
class Solution {
public int[] singleNumber(int[] nums) {
int sum = 0;//记录两个答案异或的结果
for(int i = 0; i<nums.length;i++){
sum ^= nums[i];
}
//记录两个答案第q位不同
int q = 0;
while( (sum & 1 )==0){
q++;
sum >>= 1;
}
//两个答案在第q位不同,肯定是一个为1,一个为0
//res1表示第q位为1的,res0表示第q位为0的
int res1 = 0;
int res0 = 0;
//循环异或,这里是分组的异或
for(int i = 0;i < nums.length;i++){
if( (( (nums[i]>>q) ^ sum) &1) ==0 ){
//第q位为0的一组进行异或
res0 ^= nums[i];
}else{
//第q位为1的一组进行异或
res1 ^= nums[i];
}
}
return new int[]{res1,res0};
}
}
这里再记录一下另一种查找二进制低位第一个不相同的位的方法
class Solution {
public int[] singleNumber(int[] nums) {
int sum = 0;
for(int i = 0; i<nums.length;i++){
sum ^= nums[i];
}
// sum & -sum 得到的这个数的1出现在哪,那么就是哪个位不同
sum = sum == Integer.MIN_VALUE ? sum : (sum & -sum);
int res1 = 0;
int res0 = 0;
for(int i = 0;i < nums.length;i++){
if( (nums[i]&sum) ==0 ){
res0 ^= nums[i];
}else{
res1 ^= nums[i];
}
}
return new int[]{res1,res0};
}
}