位运算
数组中数字出现的次数
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。由于时间复杂度排除暴力法,空间复杂度排除哈希表(如果哈希表的化可以用reduce加map),由于只有两个数字不同,其他都有两个,可以采用位运算中的异或,而且异或运算符合交换律,即与顺序无关
思路:
1.我们先考虑一个比较简单的情况,即nums里面只有一个数字不重复,其余都是出现了两次
那么我们直接全员异或,最后得到的值即为这个非重复的值 用一个函数来说明Func(nums)=target
2.这个题中有两个数字只出现了一次,如果我们还是采用第一个 方法的化,返回值为两个数的异或值
比如这两个不同的值为x ,y 那么target=x^y(x与y异或的结果)
3.可以考虑将nums分成两个组,每个组中各有一个只出现一次的值,而且保证出现两次的元素一定处于同一个分组内,即不会出现一个元素出现了两次,但是分属于不同分组
4.我们如何划分这个分组喃,x,y转为二进制之后,因为两个元素都不同,所以必定存在某一位不相同的情况,我们就以这个位置为准,将这个位置为0的所有元素分到同一个组,为1的分到另一个组,能不能满足我们之前的限制喃,相同元素的指定位置肯定是一样的,所以可以满足
5.如何找到这个位置喃,既然我们要找位置上不同的,那么它们异或的结果肯定是1,我们需要找到target中第一个1的位置,找不同,与运算肯定是最好的,我们从最小位开始找
n=target,m=1
while n&m==0
m<<=1
找到之后我们按照这个再进行分组就好
x=0,y=0
for(let i=0;i<nums;i++){
if(nums[i]&m) x=x^nums[i]
else{y=y^nums[i]}
}
return x,y
var singleNumbers = function(nums) {
let x=0,y=0//用于存放返回值
let target=0,m=1//target用于保存两数异或的值,m为检测1的位置的初始值
//先遍历整个元素
for(let i=0;i<nums.length;i++){
target=target^nums[i]
}
//找到target中1的位置
while((target&m)==0){//这里位运算记得加括号,否正最后返回为number值而非Boolean值
m<<=1
}
for(let i=0;i<nums.length;i++){
if(nums[i]&m){x=x^nums[i]}
else{y=y^nums[i]}
}
return [x,y]
};