位运算实用指南 🔧
一、为什么要学习位运算? 🤔
在前端开发中,合理使用位运算可以:
- 提高代码执行效率
- 优化内存使用
- 简化某些数学运算
- 实现一些有趣的功能
二、位运算基础知识 ⚡
1. 常用位运算符
js
& (与) // 两位都为1时才为1
| (或) // 只要有一位为1就为1
^ (异或) // 两位不同时为1
~ (取反) // 0变1,1变0
<< (左移) // 向左移动指定位数
>> (右移) // 向右移动指定位数三、经典问题解析 💡
1. 计算二进制中1的个数(汉明重量)
解法一:循环左移判断
js
while ((line = await readline())) {
let res = 0;
for (let i = 0; i < 32; i++) {
// 利用1的循环左移和原数据进行与运算
// 每次判断一个位置是否为1
if ((line & (1 << i)) !== 0) {
res++;
}
}
console.log(res);
}解法二:循环右移统计
js
while ((line = await readline())) {
let res = 0;
for (let i = 0; i < 32; i++) {
// 每次取最低位判断是否为1
res += (line & 1);
// 右移一位,继续判断
line >>= 1;
}
console.log(res);
}解法三:巧用 n & (n-1)
js
while ((line = await readline())) {
let res = 0;
while (line != 0) {
// n & (n-1) 可以消除最后一个1
// 例如:110100 & 110011 = 110000
line = line & (line - 1);
res++;
}
console.log(res);
}2. 不用加减乘除做加法
js
function Add(num1, num2) {
while (num2 !== 0) {
// 异或运算得到原位和
const sum = num1 ^ num2;
// 与运算后左移得到进位值
const carry = (num1 & num2) << 1;
num1 = sum;
num2 = carry;
}
return num1;
}
// 使用示例
console.log(Add(5, 7)); // 123. 数组中只出现一次的两个数字
解法一:Map方法
js
function FindNumsAppearOnce(array) {
// 使用Map记录每个数字出现的次数
const map = new Map();
array.forEach(x => {
map.set(x, (map.get(x) || 0) + 1);
});
// 过滤出现次数为1的数字并排序
return Array.from(map.keys())
.filter(x => map.get(x) === 1)
.sort((a, b) => a - b);
}解法二:位运算法
js
function FindNumsAppearOnce(array) {
// 1. 所有数字异或,得到两个单次出现数字的异或结果
let xorResult = 0;
array.forEach(num => {
xorResult ^= num;
});
// 2. 找到异或结果中第一个为1的位置
// 这个1表示两个目标数字在这一位上不同
const mask = xorResult & (-xorResult);
// 3. 根据这一位将数组分成两组
let num1 = 0, num2 = 0;
array.forEach(num => {
if (num & mask) {
num1 ^= num; // 第一组
} else {
num2 ^= num; // 第二组
}
});
return [num1, num2].sort((a, b) => a - b);
}
// 使用示例
console.log(FindNumsAppearOnce([1,2,3,3,2,9])); // [1,9]4. 求1+2+3+...+n
解法一:利用短路运算
js
function Sum_Solution(n) {
// 利用&&短路特性实现递归终止
// n > 0为true时继续递归,为false时返回n
n && (n += Sum_Solution(n - 1));
return n;
}解法二:利用位运算
js
function Sum_Solution(n) {
// 使用公式:(n+1)*n/2
// 除以2可以用右移1位代替
return (n * (n + 1)) >> 1;
}四、实战应用 🚀
1. 权限控制
js
class Permission {
static READ = 1; // 0001
static WRITE = 2; // 0010
static UPDATE = 4; // 0100
static DELETE = 8; // 1000
constructor() {
this.permission = 0;
}
// 添加权限
addPermission(permission) {
this.permission |= permission;
}
// 检查权限
hasPermission(permission) {
return (this.permission & permission) === permission;
}
}
// 使用示例
const userPermission = new Permission();
userPermission.addPermission(Permission.READ | Permission.WRITE);
console.log(userPermission.hasPermission(Permission.READ)); // true五、性能优化建议 ⚡
使用位运算代替简单的数学运算:
- 乘2:
n << 1 - 除2:
n >> 1 - 判断奇偶:
n & 1 - 取整:
n >> 0
- 乘2:
注意事项:
- 代码可读性优先
- 添加清晰的注释
- 考虑数值范围
- 处理边界情况
六、练习题推荐 📝
- LeetCode 136: 只出现一次的数字
- LeetCode 137: 只出现一次的数字 II
- LeetCode 260: 只出现一次的数字 III
- LeetCode 338: 比特位计数