神奇的位运算 n & (n - 1)

123 阅读1分钟

今天的LeetCode每日一题是 2032.至少在两个数组中出现的值。题目本身比较简单,是要给出三个数组中至少在两个数组中出现过的值,只需要遍历给出的所有的数组做标记然后判断就行了。 不过官方题解中给出了一个使用二进制位来标记的方法。使用二进制的前三位来标记是否存在于三个数组中,最后判断是否出现过两次的部分比较有趣。

var twoOutOfThree = function(nums1, nums2, nums3) {
    const map = new Map();
    for (const i of nums1) {
        map.set(i, 1);
    }
    for (const i of nums2) {
        map.set(i, (map.get(i) || 0) | 2);
    }
    for (const i of nums3) {
        map.set(i, (map.get(i) || 0) | 4);
    }
    const res = [];
    // 判断是否至少出现在两个数组中
    for (const [k, v] of map.entries()) {
        if ((v & (v - 1)) !== 0) {
            res.push(k);
        }
    }
    return res;
};

这里就比较神奇,为什么 n & (n - 1)可以判断出一个数字是否有超过1个二进制位为1?

查询资料之后发现这是按位与运算的一个小特性,将一个数与它减一进行按位与运算,得到的结果是一个二进制1数量减1的数字,所以这里判断一次就可以得到结果。 参考