JavaScript 中有几个位运算符,它们是用来直接操作二进制位的,不是经常用。最近在看算法相关的东西,所以抽时间比较系统的了解了一下。以下是常见的位运算符以及它们的功能:
功能
按位与(&):
- 描述:对两个数的每一个比特位执行与操作,如果两个相应的位都是1,则结果为1,否则为0。
- 示例:
10 & 6 = 2
按位或(|):
- 描述:对两个数的每一个比特位执行或操作,如果两个相应的位中至少有一个为1,则结果为1,否则为0。
- 示例:
10 | 6 = 14
按位异或(^):
- 描述:对两个数的每一个比特位执行异或操作,如果两个相应的位相异,则结果为1,否则为0。
- 示例:
10 ^ 6 = 12
按位非(~):
- 描述:对一个数的每一个比特位执行非操作,将1变为0,将0变为1。
- 示例:
~10 = -11
左移(<<):
- 描述:将一个数的所有比特位向左移动指定的位数,右侧用0填充。
- 示例:
10 << 2 = 40
带符号右移(>>):
- 描述:将一个数的所有比特位向右移动指定的位数,左侧用原来的符号位填充。
- 示例:
-10 >> 2 = 3
无符号右移(>>>):
- 描述:将一个数的所有比特位向右移动指定的位数,左侧用0填充。
- 示例:
10 >>> 2 = 2
位运算算法
一个经典的位运算算法题是“只出现一次的数字”(Single Number)。题目描述如下:
题目:
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
示例:
输入: [4, 3, 2, 4, 2]
输出: 3
说明:
你的算法应该具有线性时间复杂度。你可以不使用额外空间来实现吗?
解题思路:
可以使用异或运算符来解决这个问题。异或运算具有交换律和结合律,对于任何数 x
,x ^ x = 0
,x ^ 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 数字的细节,如有符号整数和溢出等问题。
评论 (0)