力扣网 题目 链接
https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/
对应官方解答 链接
https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/solution/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-by-leetcode/
本文主要是 官方的代码 细解
题目
细解过程
什么是异或
异或的性质
图解具体过程
一些例子具体过程的验证(选看,因人而异,可能较乱)
弄懂原理后自己写一遍代码
//位运算
//异或,得到 要找的两个数的异或值
//从末端开始 依次往前递推(左移1位), 直到找到 不同的位
异或值res位是1的话代表 位不同
异或值res位是0的话代表 位相同
//与运算,判断不同的位 是1 或0 区分
class Solution{
public int[] singleNumbers(int[] nums){
int res=0;
for(int i=0;i<nums.length;i++){
res^=nums[i];
}
int div=1;
if(div&res!=1){
div<<=1;
}
int a=0,b=0;
for(int i=0;i<nums.length;i++){
if(nums[i]&div==1){
a^=nums[i];
}
else b^=nums[i];
}
return [a,b];
}
}
自己写的代码的易错点总结
以上代码报错,语法易错:
1.java中 数组是大括号 return new int[] {a,b} 或者 int[] c= {a,b}; return c;
2.逻辑运算符 前面的 位运算符 要加括号,否则报错; if((div&res)!=1) if( (nums[i]&div) == 1 )
3.if(div&res!=1) 依次往前递推 应该用 while(div&res!=1)
4. while(div&res!=1) 和 while((div & res) == 0){
不一样; 前者陷入 死循环
例子:10(2)和11(3) 10^11=01 01&1=1 01==1
例子:101(5)和111(7) 101^111=010(2) 010&1=0 0!=1
例子:101(5)和101(5) 101^101=000(0)
结论: 异或结果 和 1 与运算 的结果只能 通过0来确认 ;从而判断是否为相同的数
5. if( (nums[i]&div)!=1) 和 if( (nums[i]&div)!=0) 的运算结果不一样; 前者错误
例子: div=1,10,100,1000
结论: div 和 一个数 与运算 的结果只能 通过0来确认 ;从而判断 该位为1或0;
通过1来确认是错误的做法
修正后的正确代码
class Solution{
public int[] singleNumbers(int[] nums){
int res=0;
//for(int i=0;i<nums.length;i++){
// res^=nums[i];
//}
for(int n : nums){
res ^= n;
}
int div=1;
while((div & res)==0){
div<<=1;
}
int a=0,b=0;
for(int i=0;i<nums.length;i++){
if( (nums[i]&div)!=0){
a^=nums[i];
}
else b^=nums[i];
}
int[] c= {a,b};
return c;
}
}