新闻中心
Python位运算:高效统计整数二进制表示中的连续前导1

本文详细介绍了如何在Python中利用位运算高效地统计一个整数二进制表示中连续前导1的数量。该方法通过巧妙地构造全1掩码并进行位异或操作,避免了字符串转换的开销,显著提升了性能。文章将深入解析核心算法,提供代码示例及性能对比,展示位操作在处理二进制数据时的强大优势。
1. 理解问题:统计连续前导1
在处理整数的二进制表示时,有时我们需要统计其从最高位开始连续的“1”的数量。例如,整数 6 的二进制表示是 0b110,其连续前导1的数量是 2。整数 7 的二进制表示是 0b111,其连续前导1的数量是 3。
下表展示了一些整数及其二进制表示和连续前导1的数量:
| 整数 | 二进制表示 | 连续前导1的数量 |
|---|---|---|
| 0 | 0b0 | 0 |
| 1 | 0b1 | 1 |
| 2 | 0b10 | 1 |
| 3 | 0b11 | 2 |
| 4 | 0b100 | 1 |
| 5 | 0b101 | 1 |
| 6 | 0b110 | 2 |
| 7 | 0b111 | 3 |
虽然可以通过将整数转换为字符串(如 f"{x:b}0".index("0"))来解决
此问题,但这种方法涉及字符串操作,可能带来额外的性能开销。本教程的目标是探索一种纯粹基于位运算的高效解决方案。
2. 位运算解决方案
核心思想是利用位异或操作来“反转”目标整数的位,并结合 bit_length() 方法来计算前导1的数量。
2.1 核心算法
def count_leading_ones(n: int) -> int:
"""
使用位运算统计整数二进制表示中连续前导1的数量。
"""
if n == 0:
return 0
# 1. 获取整数的实际位长度
# 例如,对于 6 (0b110),bit_length() 返回 3
# 对于 7 (0b111),bit_length() 返回 3
original_bit_length = n.bit_length()
# 2. 创建一个与 n 具有相同位长度的全1掩码
# 例如,如果 original_bit_length 是 3,则 (1 << 3) - 1 得到 0b111 (7)
all_ones_mask = (1 << original_bit_length) - 1
# 3. 将 n 与全1掩码进行位异或操作
# 异或操作的效果是:如果对应位相同则为0,不同则为1。
# 结合全1掩码,这意味着 n 中的 0 变为 1,1 变为 0。
# 例如: n = 0b110 (6)
# all_ones_mask = 0b111 (7)
# inverted = 0b110 ^ 0b111 = 0b001 (1)
# 例如: n = 0b111 (7)
# all_ones_mask = 0b111 (7)
# inverted = 0b111 ^ 0b111 = 0b000 (0)
inverted = (n ^ all_ones_mask)
# 4. 计算反转后数字的位长度
# 对于 inverted = 0b001 (1),bit_length() 返回 1
# 对于 inverted = 0b000 (0),bit_length() 返回 0
inverted_bit_length = inverted.bit_length()
# 5. 结果是原始位长度减去反转后数字的位长度
# 这个差值代表了原始数字中前导1的数量。
# 例如: original_bit_length = 3, inverted_bit_length = 1 => 3 - 1 = 2 (正确 for 0b110)
# 例如: original_bit_length = 3, inverted_bit_length = 0 => 3 - 0 = 3 (正确 for 0b111)
return original_bit_length - inverted_bit_length2.2 算法解释
- n.bit_length(): Python的 int.bit_length() 方法返回表示该整数所需的最小位数,不包括符号位和任何前导零。例如,6 (0b110) 的 bit_length() 是 3,7 (0b111) 的 bit_length() 也是 3。这个值代表了我们关注的二进制表示的“总长度”。
- all_ones_mask = (1 : 这一步是创建一个与 n 具有相同有效位长度的全1掩码。
- 1
- 减去 1 后,0b1000 - 1 得到 0b111 (7),即一个由 original_bit_length 个 1 组成的数。这个掩码确保了我们只在 n 的有效位范围内进行操作。
-
inverted = (n ^ all_ones_mask): 这是关键一步。位异或操作(^)会比较两个数的对应位:如果相同则结果位为0,如果不同则结果位为1。当 n 与一个全1掩码进行异或时,实际上是反转了 n 中对应位的值。
- 例如,如果 n 的某位是 1,与掩码中的 1 异或后变为 0。
- 如果 n 的某位是 0,与掩码中的 1 异或后变为 1。
- 这样,原始数字中的前导 1 序列会变成前导 0 序列,而第一个 0 则会变成 1。
-
original_bit_length - inverted.bit_length():
- 当 n 的前导 1 被反转为 0 后,这些 0 不再计入 inverted.bit_length()。
- 例如,对于 n = 0b110,original_bit_length = 3。反转后 inverted = 0b001,其 bit_length() 是 1。
- 3 - 1 = 2,这正是 0b110 的连续前导1的数量。
- 对于 n = 0b111,original_bit_length = 3。反转后 inverted = 0b000,其 bit_length() 是 0(因为0不需要任何位来表示)。
- 3 - 0 = 3,这正是 0b111 的连续前导1的数量。
3. 代码实现与示例
下面是完整的Python函数实现,并展示了其使用方式:
def count_leading_ones(n: int) -> int:
"""
使用位运算统计整数二进制表示中连续前导1的数量。
"""
if n == 0:
return 0
original_bit_length = n.bit_length()
all_ones_mask = (1 << original_bit_length) - 1
inverted = (n ^ all_ones_mask)
inverted_bit_length = inverted.bit_length()
return original_bit_length - inverted_bit_length
# 示例:计算0到7的连续前导1数量
print("--- 0到7的连续前导1数量 ---")
for i in range(8):
print(f"{i} {bin(i)}: {count_leading_ones(i)}")
# 更多示例
print("\n--- 更多示例 ---")
print(f"15 (0b1111): {count_leading_ones(15)}") # 4
print(f"8 (0b1000): {count_leading_ones(8)}") # 1
print(f"12 (0b1100): {count_leading_ones(12)}") # 2
print(f"0 (0b0): {count_leading_ones(0)}") # 0运行上述代码,将得到以下输出:
Motiff妙多
Motiff妙多是一款AI驱动的界面设计工具,定位为“AI时代设计工具”
334
查看详情
--- 0到7的连续前导1数量 --- 0 0b0: 0 1 0b1: 1 2 0b10: 1 3 0b11: 2 4 0b100: 1 5 0b101: 1 6 0b110: 2 7 0b111: 3 --- 更多示例 --- 15 (0b1111): 4 8 (0b1000): 1 12 (0b1100): 2 0 (0b0): 0
4. 性能考量
与基于字符串转换的方法相比,位运算方法通常具有更高的效率,因为它直接操作数字的二进制表示,避免了字符串的创建、解析和索引等开销。
我们可以使用 timeit 模块进行简单的性能测试:
import timeit
n_test = 123456789 # 用于测试的整数
# 位运算方法
bitwise_method = lambda: n_test.bit_length() - ((n_test ^ ((1 << n_test.bit_length()) - 1)).bit_length())
# 字符串转换方法
stringify_method = lambda: f"{n_test:b}0".index("0")
print(f"测试整数: {n_test} ({bin(n_test)})")
print(f"位运算方法耗时: {timeit.timeit(bitwise_method, number=1000000):.6f} 秒")
print(f"字符串方法耗时: {timeit.timeit(stringify_method, number=1000000):.6f} 秒")运行结果可能因机器而异,但通常会显示位运算方法明显更快:
测试整数: 123456789 (0b111010110111100110100010101) 位运算方法耗时: 0.29xxx 秒 字符串方法耗时: 0.37xxx 秒
从上述结果可以看出,位运算方法比字符串转换方法快约30%,这在需要频繁执行此类操作的场景中尤为重要。
5. 总结与注意事项
- 优点: 位运算方法高效、简洁,避免了字符串操作的性能开销,尤其适用于对性能要求较高的场景。
- 适用性: 该方法适用于任何非负整数。对于负整数,Python的 bit_length() 行为不同(它会计算表示该负数所需的最小位数,包括符号位,例如 -1 的 bit_length() 是 0,-2 是 1),因此如果需要处理负数,则需要额外的逻辑来处理其二进制补码表示。本教程主要关注非负整数。
- 可读性: 虽然位运算可能不如字符串操作直观,但一旦理解了其原理,它提供了一种优雅且高效的解决方案。
通过掌握这种位运算技巧,开发者可以在Python中更高效地处理二进制数据,优化代码性能。
以上就是Python位运算:高效统计整数二进制表示中的连续前导1的详细内容,更多请关注其它相关文章!
# 源代码
# seo搜索的优点
# SEO支持是什么意思
# 临沂网站建设报价
# 十大热门关键词排名
# 德令哈seo优化招商
# 速卖通 SEO 代码
# 池州seo虾哥网络
# 上海seo如何
# 建设网站品牌
# 海口网站推广注意事项
# python
# 如何将
# 数据包
# 创建一个
# 则为
# 所需
# 适用于
# 转换为
# 掩码
# python函数
# 性能测试
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
Go语言中对Map值调用带指针接收者方法:原理与最佳实践
poki网页游戏推荐_poki免费游戏平台入口
2025年云电脑操作系统体验 | 无需本地硬件,随时随地使用高性能PC
解决Django多数据库/多Schema环境下外键迁移问题
优化HTML表单样式:解决输入框焦点跳动与元素间距问题
Win10系统服务哪些可以禁用 Win10安全优化服务列表【干货】
微信网页版官方快速登录入口 微信网页版网页版账号直达
蓝湖怎样用切图标注提对接效率_蓝湖用切图标注提对接效率【设计对接】
在J*a中如何隐藏复杂性_使用门面模式组织对象交互
b站怎么取消点赞_b站点赞取消操作方法
怎样在Excel中做仪表盘_Excel仪表盘设计与关键指标展示方法
极兔快递快件信息查询系统 极兔快递官网运单号追踪
抖音创作助手登录入口_抖音创作辅助工具官网直达
铁路12306的积分有效期是多久_铁路12306积分有效期说明
J*a里如何实现订单支付与库存同步功能_支付库存同步项目开发方法说明
蛙漫官网漫画入口地址_蛙漫在线畅读无广告弹窗
Yandex搜索引擎一键访问入口_俄罗斯Yandex官网免登录
俄罗斯Yandex搜索引擎入口_Yandex官网免登录一键访问
NetBeans Ant项目:自动化将资源文件复制到dist目录的教程
163邮箱登录密码 163邮箱忘记密码找回
ArrayList与LinkedList核心操作的Big-O复杂度分析
如何使用Rector自动化升级旧代码_通过Composer安装和配置Rector进行代码重构
铁路12306卧铺选择攻略 铁路12306下铺座位预定技巧
Excel中VLOOKUP的第四个参数是干什么用的_Excel VLOOKUP第四参数作用解析
KFC游戏互动怎么赢取优惠券_KFC线上游戏活动参与与优惠代码赢取教程
uc浏览器网页版入口 uc浏览器网页版最新网址
J*aScript动态修改指定div内所有a标签样式指南
C++如何解决segmentation fault_C++段错误调试与原因分析
windows10怎么查看本机ip_windows10命令提示符ipconfig使用
c++ dfs和bfs代码 c++深度广度优先搜索算法
圆通快递查询实时追踪 圆通物流包裹状态快速查看
Win10如何开启蓝牙功能_Windows10找不到蓝牙开关解决方法
京东单号查询入口_京东快递订单追踪入口
理解J*aScript Promise的微任务队列与执行顺序
J*a里如何实现线程安全的懒加载单例_懒加载单例实现方法解析
Win11怎么查看电脑配置_Win11硬件配置检测工具使用
解决深度学习模型训练初期异常高损失与完美验证准确率问题
期待已久:小米17 Ultra、小米首款NAS本月登场
QQ邮箱网页版快速登录 QQ邮箱邮箱账号官方入口地址
J*aScript中安全有效地处理localStorage字符串数据
Golang如何使用buffered channel提高性能_Golang buffered channel优化技巧
word中如何让数字纵向排列_Word数字纵向排列方法
韩剧圈正版入口页面_韩剧圈官网登录链接
taptap防沉迷怎么解除 taptap解除健康系统限制说明【2025最新】
Golang如何使用const iota_Go iota常量计数器讲解
在J*a中如何开发简易博客标签推荐系统_博客标签推荐项目实战解析
护手霜蹭到袖口上了如何清洗? 怎样避免留下一圈油印?
精准捕获:如何在页面中监听除特定元素外的所有点击事件
J*a应用程序首次运行自动创建文件与目录的最佳实践
没有大陆身份证/银行卡如何实名微信? 亲测有效的几种方法分享


2025-11-27
浏览次数:次
返回列表