携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情
说到位运算,我们需要先补充一下,原码/反码/补码的概念
二进制的原码/反码/补码
首先区分一下无符号数和有符号数
- 无符号数
- 每一位都表示数值,没有正负之分
- 有符号数
- 第一位是符号位,0为正数,1为负数,剩下位数表示数值
补码的概念:计算机中,是以补码方式来进行计算
- 对于正数来说,它的原码/反码/补码都一样
- 对于负数
- 反码为:符号位不变,其他位取反
- 补码位:反码+1
搞清楚原码/反码和补码的概念后,我们再来看看位运算中常见的移位运算符
移位运算符(<<, >>, >>>)
<<左移运算符- 每左移一位,相当于乘2操作
- 注意:并非所有情况都相当于*2,当左移到1为首位时,会变成负数
>>右移运算符(有符号右移,右移后补符号位)- 对于正数:右移高位补0,每右移一位,相当于除2操作,并向下取整
- 对于负数:会将补码带符号右移,高位补1,右移完成后再转为原码.
- 每右移一位,相当于除2操作,并向上取整,再加上符号位
>>>无符号右移(右移补0)- 对于正数:与
>>相同 - 对于负数:右移补0
- 对于正数:与
常见位运算
- 判断奇偶性
- x & 1 === 0 为奇数
- 清除掉最右边的1
- x & (x - 1)
- 得到最右边的1
- x & -x 或 x & (~x + 1)
下面看一道例题
191. 位1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数。 解题思路:
- 每次右移i位,如果右移后最后一位为1,则结果+1
var hammingWeight = function(n) {
let res = 0
for (let i = 0; i < 32; i++) {
res += 1 & (n >> i)
}
return res
};
这种算法的时间复杂度为O(k),k为int的2进制位数
来看另一个思路
- 用
x & (x - 1)每次清掉一个1,计数,直到清为0为止
var hammingWeight = function(n) {
let ret = 0
while (n) {
n &= n-1
ret++
}
return ret
};
时间复杂度为O(logn)