题目
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
思路
- 两个不同的数字异或结果肯定会有位数是1,两个相同的数字异或结果是0
- 循环数组进行异或,最后的结果就是两个不同数字异或的结果
- 设置mark,用来记录为1的位数。与异或结果进行&运算,最后得到的结果就是一个全部为0只有一位为0的数字,相当与是记录了为1的位数(会有好几个,有一个就行)。即表示两个不同的数字在位数上不同的位置
- 将所有数字与mark进行与运算,如果结果是0,说明该为不是1,分为一组,如果结果是1,说明该位是1,分为一组。相同的数字一定在同一组会抵消,那么两边各自剩下的数字就是不同的数字
- 位运算总结
- 乘除——n<<1 n*2 ; n>>1 n除2
- 奇偶判断——n&1==1 奇数(其实类似于将与1进行与运算,就将数字分成两类。那么和别的数字进行与运算,也可以分成两类)
代码
public int[] singleNumbers(int[] nums) {
int res = 0;//存储所有数字异或的结果
for(int num:nums){
res ^=num;
}
//相同的数字为0抵消,此时的res是两个不同的数异或出来的结果
//找到两个数字不同的位数,也就是为1的位,会有很多个,找到一个就可以
int mark = 1;
while((res&mark)==0){
mark<<=1;
} //mark中的1就是不同的位置
//分成两组
int a = 0;
int b = 0;
for(int num:nums){
//把该位是0的放到一组,剩下的放到一组。重复的数字会抵消,剩下的就是两个不同的数字
if((num & mark)==0){
a^=num;
}else{
b^=num;
}
}
return new int[]{a,b};
}