「前端刷题」260.只出现一次的数字 III(MEDIUM)

118 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情

题目(Single Number III)

链接:https://leetcode-cn.com/problems/single-number-iii
解决数:878
通过率:73%
标签:位运算 数组 
相关公司:amazon bytedance facebook 

给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。

 

示例 1:

输入: nums = [1,2,1,3,2,5]
输出: [3,5]
解释: [5, 3] 也是有效的答案。

示例 2:

输入: nums = [-1,0]
输出: [-1,0]

示例 3:

输入: nums = [0,1]
输出: [1,0]

 

提示:

  • 2 <= nums.length <= 3 * 104
  • -231 <= nums[i] <= 231 - 1
  • 除两个只出现一次的整数外,nums 中的其他数字都出现两次

思路

  1. 如果只有一个数,我们知道可以用亦或,一次搞定
  2. 如果有两个单数a和b,那么同样的一次遍历后的结果是 a ^ b 记做 res
  3. a和b两个数肯定不一样,所以 res肯定至少有一位是 1,并且整个数组的数字,按照这个位是0或者1,分为两部分的数,我们遍历一部分,就能找出其中一个数
  4. 关键就是找出这个1 ,我们找最右边的那个1
  5. 公式就是 res & (~res + 1) ,可以自己写一下,记做 right
  6. 遍历数组,如果元素 & 这个right是0,代表这个数的这个位是0,只操作这个0
  7. 得到其中一个数记做res1 ,另外一个数用 res亦或 res1 操作即可

代码

var singleNumber = function(nums) {
  let res = 0;
  nums.forEach(e => {
    res = res ^ e;
  })
  // res 就是 a ^ b 
  let right = res & (~res + 1);
  // a和b必然最后某一位不同,一个是0,一个是1
  let res1 = 0;
  nums.forEach(e => {
    if((e & right) === 0){
      res1 ^= e;
    }
  })
  return [res1, res ^ res1]
};

思路2

遍历找出只出现一次的数字

代码

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var singleNumber = function(nums) {
    const { length } = nums;
    let res = {};
    for(let i = 0; i < length; i++){
        if (res[nums[i]] !== undefined) {
            delete res[nums[i]];
        } else {
            res[nums[i]] = nums[i];
        }
    }
    return Object.values(res);
};