位运算算法题

107 阅读2分钟

题目:一个整型数组 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];

    var singleNumbers = function(nums) {
    //输入[4,1,4,6]  => [6,1]
    //设置变量,a存放两个不重复数的异或值。b,c分别表示这两个数
    //所以 b ^ c = a
    let a,b,c;
    //通过异或去重,得到这两个不重复数异或的值
    for(let item of nums){ a ^=item }
    // x & (-x)本身的作用是得到最低位的1
    // 利用这个1来进行分组,也就是做到将A和B区分开
    b = a & (~a + 1);
    // 根据二进制位上的那个“1”进行分组
    // 需要注意的是,分组的结果必然是相同的数在相同的组,且还有一个结果数
    // 因此每组的数再与c=0一路异或下去,最终会得到那个结果数A或B
    // 且由于异或运算具有自反性,因此只需得到其中一个数即可
    for(let item of nums)  if(b & item) c ^= item;
    return [c, a ^ c]
};

理解:
以示例二举例,得到的是 2 和 10。
转换为 二进制分别是: 10 和 1010。
两数异或得到的是1000。
1000 & -1000 得到的是两数(2和10)异或值的最右边的1。
(两数异或值的任何一个1,都能把两个数分开,因为能存在1,其中一个数的这个位必为1,但0不行)
10 和 1010中必有一个数的位数满足这个1的这个值,所以可根据 & 对数组进行分组。