JavaScript 位运算符

Flying
2024-01-10 / 0 评论 / 32 阅读 / 正在检测是否收录...

JavaScript 中有几个位运算符,它们是用来直接操作二进制位的,不是经常用。最近在看算法相关的东西,所以抽时间比较系统的了解了一下。以下是常见的位运算符以及它们的功能:

binary-code.svg

功能

  1. 按位与(&):

    • 描述:对两个数的每一个比特位执行与操作,如果两个相应的位都是1,则结果为1,否则为0。
    • 示例:10 & 6 = 2
  2. 按位或(|):

    • 描述:对两个数的每一个比特位执行或操作,如果两个相应的位中至少有一个为1,则结果为1,否则为0。
    • 示例:10 | 6 = 14
  3. 按位异或(^):

    • 描述:对两个数的每一个比特位执行异或操作,如果两个相应的位相异,则结果为1,否则为0。
    • 示例:10 ^ 6 = 12
  4. 按位非(~):

    • 描述:对一个数的每一个比特位执行非操作,将1变为0,将0变为1。
    • 示例:~10 = -11
  5. 左移(<<):

    • 描述:将一个数的所有比特位向左移动指定的位数,右侧用0填充。
    • 示例:10 << 2 = 40
  6. 带符号右移(>>):

    • 描述:将一个数的所有比特位向右移动指定的位数,左侧用原来的符号位填充。
    • 示例:-10 >> 2 = 3
  7. 无符号右移(>>>):

    • 描述:将一个数的所有比特位向右移动指定的位数,左侧用0填充。
    • 示例:10 >>> 2 = 2

位运算算法

一个经典的位运算算法题是“只出现一次的数字”(Single Number)。题目描述如下:

题目:

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

示例:

输入: [4, 3, 2, 4, 2]
输出: 3

说明:

你的算法应该具有线性时间复杂度。你可以不使用额外空间来实现吗?

解题思路:

可以使用异或运算符来解决这个问题。异或运算具有交换律和结合律,对于任何数 xx ^ x = 0x ^ 0 = x
关于位运算有下面几个规律

1 ^ 1 = 0;
1 ^ 0 = 1;
0 ^ 1 = 1;
0 ^ 0 = 0;

也就说 0 和 1 异或的时候相同的异或结果为 0,不同的异或结果为1,对于任何数 a,有下面几个规律

a ^ a = 0; // 自己和自己异或等于 0
a ^ 0 = a; // 任何数字和 0 异或等于他自己
a ^ b ^ c = a ^ c ^ b; // 异或运算具有交换律

有了这个规律,这题就很容易解了,我们只需要把所有的数字都异或一遍,最终结果就是只出现一次的数字。

var singleNumber = function(nums) {
  let result = 0;
  for (let num of nums) {
    result ^= num;
  }
  return result;
};

// 示例用法
console.log(singleNumber([4, 3, 2, 4, 2]));  // 输出: 3
本题用到异或位赋值运算符 ^=,把所有的数字都异或一遍,结果就是4 ^ 4 ^ 2 ^ 2 ^ 3 = 3

这个算法的时间复杂度是 O(n),其中 n 是数组的长度。空间复杂度是 O(1),只使用了常数额外的空间,满足了题目的要求。

总结

这些位运算符通常用于一些高效的位级操作,例如权限控制、图形处理等。在实际应用中,需要注意位运算可能涉及到一些 JavaScript 数字的细节,如有符号整数和溢出等问题。

1

评论 (0)

取消