前置知识
异或运算
- 将2个数的二进制位按位运算,相同的结果为0,不同结果为1.
异或运算性质
- 任何数和0异或结果为任何数
- 任何数和自己异或结果为0
- 异或运算满足交换律
只出现一次的数字(1)
数组中只有一个数字出现一次,其他数字均出现两次。
利用异或,两个相同的数异或为0,任何数与0异或为自己,将这组数字全员异或,得到的结果为出现一次的数字。
class Solution {
public int[] singleNumbers(int[] nums) {
int ret = 0;
for(int i=0; i<nums.length; i++){
ret = ret^nums[i];
}
return ret;
}
}
只出现一次的数字(2)
较上题来说,难度增加,这组数字有两个出现次数为1的数字。
这次还能直接套用上题的方法吗?
可以是可以,不过还要制造这个机会。
如果单纯的按照全员异或的方式一遍得出的结果是两个出现一次的数字异或的结果。显然结果是不对的。
如果能将这组数分成两组,且刚好一组有一个出现一次的数字,在这两组上分别全员异或一次,就可得到答案。
如何分组?
可以从这组数全员异或的结果下手。
因为这两个数字不同且出现次数均为1,则他们异或的结果中肯定有一位是1。
这个1就代表他们这位是不同的。而二进制数的一位只有两种结果,1/0。
利用这个条件,将此位为1的数分在一组,为0的数分在一组。
class Solution {
public int[] singleNumbers(int[] nums) {
int ret = 0;
for(int i=0; i<nums.length; i++){
ret = ret^nums[i];
}
int tmp = ret & (-ret);
ret = 0;
int ret1=0;
for(int i=0; i<nums.length; i++){
if((nums[i]&tmp) == 0){
ret = ret^nums[i];
}else{
ret1 = ret1^nums[i];
}
}
int[] arr = {ret1,ret};
return arr;
}
}