对异或印象最深刻的记忆还是大一下的数字逻辑课,可那时仅仅知道不同为1,最近又学到了异或运算,故作此文。
下面列出几个异或的常见性质
- 异或可以理解为无进位相加
- 满足交换律和结合律
- a^a = 0 ,a^0 = a
- 如果a^b = c ① ,那么 b = a^c ② a = b^c
以下是第四条性质的证明
① 两边同时异或 a,即可得到②(难以想象我当时为什么想了那么久)
交换两个数
1 2 3 4
| int a , b; a = a ^ b; b = a ^ b; a = a ^ b;
|
交换逻辑是上述第三点性质,值得注意的是,交换的两个值应该是内存中两块不一样的内存,所以在数组中,不能出现同一个值用这种方法比较
不用任何判断语句和比较操作,返回两个数的最大值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public static int sign(int n){ return flip(n << 31); } public static int flip(int n){ return n ^ 1; } public static int getMax1(int a,int b){ int c = a - b; int returnA = sign(c); int returnB = flip(returnA); return a * returnA + b * returnB; } public static int getMax2(int a,int b){ int c = a - b; int sa = sign(a); int sb = sign(b); int sc = sign(c); int diffAB = sa ^ sb; int sameAB = flip(diffAB);
int returnA = diffAB * sa + sameAB * sc; int returnB = flip(returnA); return a * returnA + b * returnB; }
|
找到缺失的数字
268. 丢失的数字
依据上面提到的第四条性质解答
1 2 3 4 5 6 7 8 9 10 11 12
| public int missingNumber(int[] nums) { int eorAll = 0,eorHas = 0; for(int i = 0;i < nums.length ;i++ ){ eorAll ^= i; eorHas ^= nums[i]; } eorAll ^= nums.length; return eorAll ^ eorHas; }
|
数组中1个数出现了奇数次,而其他数都出现了偶数次,返回出现了奇数次的数
只出现一次的数字
本解法适用于一个数出现偶数次,其他数出现奇数次的情况
1 2 3 4 5 6 7
| public int singleNumber(int[] nums) { int ans = 0; for(int i = 0 ;i < nums.length ; i++){ ans ^= nums[i]; } return ans; }
|
数组中2个数出现了奇数次,而其他数都出现了偶数次,返回这两个出现了奇数次的数
260. 只出现一次的数字 III
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public int[] singleNumber(int[] nums) { int eor1 = 0,eor2 = 0; for(int i = 0;i < nums.length;i++){ eor1 ^= nums[i]; } int rightone = eor1 & (-eor1); for(int num : nums){ if((num & rightone) == 0){ eor2 ^= num; } } return new int[] {eor2,(eor1 ^ eor2)}; }
|
数组中只有一个数的出现次数小于m次,其他数出现次数都等于m次,返回这个出现次数小于m次的数
137. 只出现一次的数字 II
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public int singleNumber(int[] nums) { return find(nums,3); } public int find(int[] nums ,int m){ int[] cnts = new int[32]; for(int num : nums){ for(int i = 0;i < 32;i++){ cnts[i] += (num >> i) & 1; } } int ans = 0; for(int i = 0;i < 32;i++){ if((cnts[i] % m) != 0 ){ ans |= (1 << i); } } return ans; }
|