上一章咱们认识了按位操做符, 这一章咱们整理一下按位运算的经典案例html
使用按位操做符的数,会先转成 32 位比特序列,也就是32 位的有符号的整数markdown
若是这个数是正数,若是大于 ,只会保留低 32 位, 高于 32 位的数不存储;app
若是这个数是负数,若是小于 ,只会保留低 32 位, 高于 32 位的数不存储;post
两个二进制数, 它们对应位的数只有 1 个 1, 结果为 1, 不然, 结果为 0。spa
a ^ b ^ b = a
a ^ b = b ^ a
a ^ (b ^ c) = (a ^ b) ^ c
a ^ 0 = a
a ^ a = 0
12.12 ^ 0 //12
Math.PI ^ 0 //3
复制代码
JavaScript 默认将数字存储为 64 位浮点数,但按位运算都是以 32位的二进制整数执行。code
两个相同的数按位运算后, 结果只会保留整数部分,小数部分不存储。orm
Infinity ^ 0 //0
Number.MAX_VALUE ^ 0 //0
复制代码
若是一个数大于 , 按位运算时只会保留低 32 位运算, 高于 32位的数丢弃, 结果就不许确了。xml
3 ^ 3 //0
12.12 ^ 12.12 //0
复制代码
let a = 3, b =5;
a = a ^ b;
b = a ^ b; // 分解开就是 (a ^ b) ^ b, 根据自反性得知,结果为 a,a 赋值给 b
a = a ^ b; // 分解开就是 a ^ (a ^ b), 根据自反性得知,结果为 b,b 赋值给 a
console.log(a, b) // 5, 3
复制代码
咱们画图看一下:htm
a = 3 (base 10) = 00000000000000000000000000000011 (base 2)
b = 5 (base 10) = 00000000000000000000000000000101 (base 2)
--------------------------------
3 ^ 5 (base 10) = 00000000000000000000000000000110 (base 2) = 6 (base 10) = a
//如今 a = 6了
a = 6 (base 10) = 00000000000000000000000000000110 (base 2)
b = 5 (base 10) = 00000000000000000000000000000101 (base 2)
--------------------------------
6 ^ 5 (base 10) = 00000000000000000000000000000011 (base 2) = 3 (base 10) = b
//如今 b = 3 了, 已经把 a 的值交换给 b 了
a = 6 (base 10) = 00000000000000000000000000000110 (base 2)
b = 3 (base 10) = 00000000000000000000000000000011 (base 2)
--------------------------------
6 ^ 3 (base 10) = 00000000000000000000000000000101 (base 2) = 5 (base 10) = a
复制代码
通过三次 ^
操做后, 咱们把 a 和 b的值交换成功了。
1-1000放在含有1001个元素的数组中,只有惟一的一个元素重复,找出这个重复的数字。
设重复的数为 x, 根据自反性能够获得:
(1 ^ 2 ...... 999 ^ 1000)^ (1 ^ 2 ...... 999 ^ 1000 ^ x) = x
复制代码
找出惟一一个在数组中出现一次的整数,而其余都会出现两次。
咱们知道两个相同的数异或为 0
, 那么把数组中的全部整数异或运算, 剩下的就是惟一出现一次的数。
let arr = [1,2,1,2,3]
let value = arr.reduce((p, c) => p ^ c)
console.log(value) //3
复制代码
一个整型数组
nums
里除两个数字以外,其余数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
咱们把这一题拆分红上面的那道题就好作了,拆分红两个数组分别异或。
const nums = [1, 4, 3, 4]
const x = nums.reduce((p, c) => p ^ c) //x = a ^ b
let mark = 1;
//两个不相同的数, 异或对应位的数字至少有 1 位不相同, 咱们找出这个数.
while((x & mark) === 0) mark <<= 1;
let xor1 = 0;
let xor2 = 0;
for (let n of nums) {
if(n & mark){
xor1 ^= n;
}else{
xor2 ^= n;
}
}
console.log(xor1, xor2) //3,1
复制代码
设 两个不一样的数是 a 和 b
x = a ^ b
a ^ b
的结果x
确定不为 0,那么至少有 1 位是 1, 咱们找出是哪一位?就能够分组了。mark=1
,mark 会左移, 根据 x & mark
去找最近一位的 1,若是 x & mark
等于 1, 找到位置,不然, mark 继续左移。mark
,咱们得知mark
中只有 1 位是 1, 其余位都是 0, 因此遍历nums
判断n & mark
可得出:xor1
组,不然,放到xor1
组。n & mark
的值是同样的, 确定会放在同一个 xor
中。