剑指 56-I. 数组中数字出现的次数 - 难度中等

1. 题目描述

一个整型数组 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]

限制:

2 <= nums.length <= 10000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2. 题解

1、位运算

简化版:若本题是找数组中只出现一次的1个数字,就可以将数组元素依次异或,因为相同的数字会两两相消,所以异或的结果就是答案。
进阶版:现在题目是让我们找出现一次的2个数字,过程如下:

  • 将数组元素依次异或,得到这两个只出现一次数字的异或结果;
  • 通过与运算以及有符号左移,按由右向左的顺序,得到右边第一位为1的位置(为1说明这两个数字在这一位是不同的);
  • 按照这个位置,可以将数组分为2组,这两组各包含一个只出现一次的数字;
  • 分别将这两组数字异或,得到结果即答案。
/**
 * @param {number[]} nums
 * @return {number[]}
 */
var singleNumbers = function(nums) {
    //将数组元素依次异或
    let xor = 0;
    for(let i = 0; i < nums.length; i++){
        xor = xor ^ nums[i];
    }
    //从右开始,找到异或结果里的第一个1
    let index = 1;
    while((index & xor) == 0){
        index = index << 1;
    }
    //根据数组元素中第index位置是否为1被分成两组,两组分别异或就能得到结果
    let res = [];
    res.push(0);
    res.push(0);
    for(let i = 0; i < nums.length; i++){
        if((nums[i] & index) == 0){
            res[0] = res[0] ^ nums[i];
        }else{
            res[1] = res[1] ^ nums[i];
        }
    }
    return res;
};

时间复杂度:O(n),
空间复杂度:O(1)。

顺便复习一下js中的位运算:

  1. 按位与:&
  2. 按位或:|
  3. 按位非:~
  4. 异或:^ (相同为0,不同为1)
  5. 有符号左移: << (相当于乘2^n,右边补0)
  6. 有符号右移:>> (相当于除以2^n,左边补0)
  7. 无符号右移:>>> (符号位也会跟着移动)

你可能感兴趣的:(#,java-script刷题)