原理:位运算
如果该整型数组中只有一个数字 x 出现一次,其他数字出现两次。
由于两个相同的数字异或后得0,若将 nums 中所有数字执行异或运算,留下的结果则为出现一次的数字 x。
思路:
题目中有两个数字只出现一次,nums 中所有数字执行异或运算后得到 x⊕y。
由于x≠y,则 x⊕y 二进制位中有至少一位为 1,可以根据这一位将 nums 分为两个子数组,分别包含 x 和 y。
这样两个子数组的所有数字分别进行异或运算,则可以得到 x 与 y。
根据与运算的特点,可以初始化一个辅助变量 m = 1,通过与运算从右向左循环判断,可获取 x⊕y 二进制位中第一位 1。
通过遍历判断 nums 中各数字和 m 做与运算的结果,可将数组拆分为两个子数组。
class Solution { public int[] singleNumbers(int[] nums) { int x = 0, y = 0, n = 0, m = 1; for(int num : nums) // 1. 遍历异或,得到x⊕y n ^= num; while((n & m) == 0) // 2. 循环左移,计算 m m <<= 1; for(int num: nums) { // 3. 分组 if((num & m) != 0) x ^= num; // 4. 当 num & m != 0,即 x⊕y 二进制位中第一位 1 处num != 0 else y ^= num; // 4. 即……num == 0 } return new int[] {x, y}; // 5. 结果 } }
注意:
if((num & m)!=0)这里不能写成 if((num & m)!=1)
因为 num & m 的结果不只有 0 和 1,如 2 & 2 = 2(10 & 10 = 10)
如果写成!=1,会将非0的子数组切割一部分进等于0的子数组,可能导致x、y均出现在一个子数组中,结果错误。
原文:https://www.cnblogs.com/zccfrancis/p/14444590.html