携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情
异或运算
异或运算其实是无进位相加,满足交换律和结合律
也就是
a ^ b = b ^ a
(a ^ b) ^ c = (a ^ c) ^ b
a ^ a = 0
交换两个数的异或写法如下:
let a = 3
let b = 8
a = a ^ b
b = a ^ b // a ^ b ^ b => a
a = a ^ b // a ^ b ^ a => b
// 即可交换两数
这里需要注意:异或运算做交换需要满足条件,两个数的地址不一致,如果在数组中,交换的是同一个下标位置,则会将该位置变成0
关于异或运算可以看一个例子如下:
一个数组中,1个数出现奇数次,其他数出现偶数次,求这个数
根据异或运算满足交换律和结合律,那么只需要不断异或这个数组中的每个元素,最终得到的数一定是这个奇数次的数
function getNum (arr) {
let num = 0
for (let i = 0; i < arr.length; i++) {
num ^= arr[i]
}
return num
}
一个数组中,2个数出现奇数次,其他数出现偶数次,求这2个数
根据上题,变形出的第二题
- 如果按照上述思路,全部异或,最后得到的是这两个数的异或结果a^b
- 可以通过把结果
x & -x得到最右边的1,这个1,一定是这两个奇数其中一个的某一位,假设为a而数组中其他元素的这个位置加起来一定为偶数个 - 那反向思考,这个位置不为1的数,一定包含b和其他偶数,而不包含a,这样就能求出b
- b和a^b相异或,然后就能得到a
代码如下:
function getNum2 (arr) {
let eor = 0
for (let i = 0; i < arr.length; i++) {
eor ^= arr[i]
}
let right = eor & -eor
let num = 0
for (let s of arr) {
if ((right & s) === 0) {
num ^= s
}
}
return [num, num ^ eor]
}
下面看一道例题
389. 找不同
- 依据题意,可以很容易的想到异或算法
- 但是有个问题,字符如何异或呢?需要先将字符转成ascii值,再进行异或运算,运算完成后再转回字符 代码如下:
var findTheDifference = function(s, t) {
// 对数字,相同异或为0,不同异或为1
// 对ascii异或,最后再转为字母
let ret = 0
for (let ch of s) {
ret ^= ch.charCodeAt()
}
for (let ch of t) {
ret ^= ch.charCodeAt()
}
// 转为字母
return String.fromCharCode(ret)
};