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中的位运算:
- 按位与:&
- 按位或:|
- 按位非:~
- 异或:^ (相同为0,不同为1)
- 有符号左移: << (相当于乘2^n,右边补0)
- 有符号右移:>> (相当于除以2^n,左边补0)
- 无符号右移:>>> (符号位也会跟着移动)