[路飞]_260. 只出现一次的数字 III

463 阅读2分钟

260. 只出现一次的数字 III

方法一 使用 map 额外空间

var singleNumber = function (nums) {
  // 申请一个额外空间
  let obj = {}
  //遍历数组
  nums.forEach((item) => {
    //如果当前值在空间中找不到
    if (obj[item] == undefined) {
      //记录当前值出现的次数
      obj[item] = 1
    } else {
      // 再次出现的删除
      delete obj[item]
    }
  })

  //将数据从额外空间提取出来
  let result = Object.keys(obj).map((v) => Number(v))
  return result
  console.log(obj)
}

方法二 异或

利用相同异或为 0 思路;将数组所有数据异或如果设两个只出现一次的数假设为 x1,x2;
显而易见,x 与数组所有元素异或,一定有 x = x1 ^ x2;
剩下的就比较关键了;已知 x = x1 ^ x2 怎么找出 x1,x2 呢?
首先知道的条件,x != 0 ;因为如果 x == 0;则 x1 == x2;
首先,既然 x1 !== x2;那必然后 x1 的二进制与 x2 的二进制在某一位上不同;(这个条件是重点!!!!!!,理解这句话这题就明白了);
二进制嘛,特征明显,非 0 即 1;
假设 x1 的二进制与 x2 的二进制再第 k 为不相同;那是不是第 k 位一定有一个是 0;而另一个是 1;

由以上的表述,将数组数据分为两类,一类 k 位置为 0;一类 k 位置为 1;奇妙的事情发生了;因为除了 x1,x2 外数组其他数据两两相等,那么,俩俩相等的数据一定会被分配到同一个类型中;

同一类型中相同的数据会被抵消,抵消之后一类剩余 x1,而另一类必然剩余 x2;
哈哈,是不是很熟悉,第 136 题的代码是不是出现在了眼前;
参考代码如下

var singleNumber = function (nums) {
  let x = 0
  nums.forEach((e) => {
    x = x ^ e
  })
  let x1 = 0
  let x2 = 0
  const k = x & -x
  nums.forEach((e) => {
    if (e & k) {
      x1 = x1 ^ e
    } else {
      x2 = x2 ^ e
    }
  })
  return [x1, x2]
}