剑指 Offer 56 - I. 数组中数字出现的次数
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
题意理解 找出数组中不重复的两个数 利用Map,不符合空间复杂度
- 两个不同的数为a=0,b=0; 0异或任意数为任意数
- 位运算符异或^ 两个数相同为0,假设x.y就是两个出现一次不相同的数,遍历一遍结果ret就是x^y的值
- 两个数不相同,x^y的二进制位一定不同,用div=1表示,对遍历ret&div==0,div<<=1查找到第一个进制位,即可拆分两个数
- 再次遍历数组,数组中的数据就有两种情况,一种是div&nums[i]===0)(符合条件的一个数在这里),另一种就是div&nums[i]!==0(符合条件的另一个数在这里),如果div&nums[i]===0,则a^=nums[i],否则b^=nums[i]
- a,b就是要找的数
位运算
var singleNumbers = function(nums) {
let ret = 0;
nums.forEach((n) => {
ret ^= n;
})
let div = 1;
while ((div & ret) == 0) {
div <<= 1;
}
let a = 0,
b = 0;
nums.forEach((n) => {
if ((div & n) != 0) {
a ^= n;
} else {
b ^= n;
}
})
return [a, b];
};
Map
var singleNumbers = function(nums) {
const map = new Map()
for (let i = 0; i < nums.length; i++) {
if (map.has(nums[i])) {
map.set(nums[i], 2)
} else {
map.set(nums[i], 1)
}
}
let arr = [];
map.forEach((val, key) => {
if (val === 1) {
arr.push(key)
}
})
return arr
};
剑指 Offer 56 - II. 数组中数字出现的次数 II
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
题意理解: 找出数组中只出现一次的数 位运算是都将转为32为进行计算,每位只有0和1,不能只看表象及~0因改为11111111111111111111111111111111 ~为取反0变1, 1变0 1&0=1; 1&x=x; x&~x=0 x^0=x; 1^x=~x; x^x=0 仅在二进制位中相同
- 需要标记出现一次 1 出现两次为 2 出现三次为 0
- ones 一次为1,两次三次为0;twos第二次为1,一次和三次为0
- 一次 ones = nums[i] = ones ^ nums[i] & ~nums[i] ;twos = 0 =twos ^ nums[i] & ~ones;
- 两次 ones = 0 = ones ^ nums[i] & ~nums[i] ;twos =nums[i]= twos ^ nums[i] & ~ones;
- 三次 ones = 0= ones ^ nums[i] & ~nums[i] ;twos = twos ^ nums[i] & ~ones;
var singleNumber = function(nums) {
let ones = 0,
twos = 0;
for (let i in nums) {
ones = ones ^ nums[i] & ~twos;
twos = twos ^ nums[i] & ~ones;
}
return ones;
};
遍历统计 声明一个长度为32的数组,初始数据为0 计算数组中每隔数的每位数字出现的次数,最后遍历数组,每位求余,即可计算出不同的数字
var singleNumber = function(nums) {
let arr = [];
for (let i = 0; i < 32; i++) {
arr[i] = 0;
}
nums.forEach(item => {
for (let i = 0; i < 32; i++) {
arr[i] += item & 1;
item >>>= 1
}
})
let res = 0;
for (let i = 0; i < 32; i++) {
res <<= 1
res |= arr[31 - i] % 3;
}
return res;
}