整数的二进制表达中有多少个1
整数的二进制表达中有多少个1
统计整型的二进制表达中1的个数
【题目】
给定一个整型(32位整数)n,可为0,可为正,也可为负,返回该整型二进制表达中1的个数。
无符号右移
算法思路:每次无符号右移时统计整型n为1的次数。
注意:python无符号运算,非负数有符号移位运算和无符号运算相同,因此需额外处理负数的无符号移位运算,将其转换为可以间接求的正数。
方法1:
负数1的个数可以转换为(其相反数-1)中0的个数, 即32 - (转换数中1的个数);
方法2:将负数转换为对应的无符号整数即,在统一移位计算1的个数;
相应代码
# 负数转换为(相反数-1)中0的个数, 32 - (1的个数)
def count_one1(n):
if n < -2 ** 31 or n > 2 ** 31 - 1:
return
if n == -2 ** 31:
return 1
elif n >= 0:
count = 0
while n != 0:
count += n & 1
n = n >> 1
return count
else:
count = 0
n = -n - 1
while n != 0:
count += n & 1
n = n >> 1
return 32 - count
# 统一转换成无符号数(0 ~ 2 ^ 32 - 1)
# 负数 + 2 ^ 32
def count_one2(n):
if n < -2 ** 31 or n > 2 ** 31 - 1:
return
if n < 0:
n += 2 ** 32
count = 0
while n != 0:
count += n & 1
n = n >> 1
return count
按位与移除最右侧1
算法思路:
方法3:n & (n - 1)
移除最右侧的1,统计移除次数;
方法4:n & (~n + 1)
获取最右侧的1,原数相减获取最右侧的1即移除最右侧的1,统计移除次数;
注意:n & (n - 1)
移除最右侧的1和n & (~n + 1)
获取最右侧的1是位运算常用技巧。
实际上两者等价,简单证明如下。
相应代码
# n & (n - 1)逐个移除最右侧1,统计1的个数
def count_one3(n):
if n < -2 ** 31 or n > 2 ** 31 - 1:
return
count = 0
while n != 0 and n != -2 ** 31:
n = n & (n - 1) # 移除最右侧1
count += 1
if n == -2 ** 31:
count += 1 # 统计符号位1
return count
# n & (~n + 1)获取最右侧1,统计1的个数
def count_one4(n):
if n < -2 ** 31 or n > 2 ** 31 - 1:
return
count = 0
while n != 0 and n != -2 ** 31:
n -= n & (~n + 1) # 移除最右侧1
count += 1
if n == -2 ** 31:
count += 1 # 统计符号位1
return count
平行算法
算法思路:
四次$(n ; & ; c_i) +(,(n >> i , ) ; & ; c_i) $
登峰造极之操作,大家可略微了解,加强对位运算的理解。
以-1为例,将十六进制以二进制展开,帮助大家更好地理解其中的奥妙。
的确费了很大功夫,我来解释下运算的原理及过程。
为初始值,这里为-1。
$(n ; & ; c_i) +(,(n >> i , ) ; & ; c_i) $在错位统计组1的个数,并合并累积到大组中。
为第i次操作的常数项
划横线的是本质上起作用的位置,再扩展至32位,即为整个
蓝色部分的所在的位置表示可取0,可取1,常数项可以修改
为第i次运算的结果值,为最终统计1的数量。
相应代码
最终以如图所示的常数进行运算,与左神书上一致。
# 平行算法
# 对负数有符号右移转换正数无符号右移处理
# 换常数进行测试
def count_one5(n):
if n < -2 ** 31 or n > 2 ** 31 - 1:
return
if n < 0:
n += 2 ** 32
n = (n & 0x55555555) + ((n >> 1) & 0x55555555)
n = (n & 0x33333333) + ((n >> 2) & 0x33333333)
n = (n & 0x0f0f0f0f) + ((n >> 4) & 0x0f0f0f0f)
n = (n & 0x00ff00ff) + ((n >> 8) & 0x00ff00ff)
n = (n & 0x0000ffff) + ((n >> 16) & 0x0000ffff)
return n
测试代码
以无符号右移代码为例,进行测试,其他测试用例相同。
# 简单测试
if __name__ == '__main__':
n = 0
print(count_one1(n)) # 0
n = 3
print(count_one1(n)) # 2
n = -1
print(count_one1(n)) # 32
n = -3
print(count_one1(n)) # 31
小结
位运算考察整数进制的表示和理解,建议拿笔和纸带入用例推导一番,加强训练。
有任何疑问和建议,欢迎在评论区留言和指正!
感谢您所花费的时间与精力!
推荐阅读
-
剑指offer11:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。(进制转换,补码反码)
-
剑指offer11:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。(进制转换,补码反码)
-
用c语言实现,两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?
-
1.无符号整数的二进制中1的个数2.十进制数转化为二进制数
-
求一个整数存储在内存中的二进制中1的个数
-
【C语言】——求一个整数存储在内存中二进制中的1的个数的三种方法
-
求一个整数存储在内存中的二进制中的1的个数
-
求一个整数存储在内存中的二进制中1的个数
-
C语言 求一个整数存储在内存中的二进制中1的个数
-
C语言 求一个整数存储在内存中的二进制中1的个数。