news 2026/6/10 16:56:45

从‘An Easy Problem’到‘Next Permutation in Bits’:一个二进制问题的通用解法与LeetCode实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从‘An Easy Problem’到‘Next Permutation in Bits’:一个二进制问题的通用解法与LeetCode实战

从二进制排列到算法实战:解码"下一个相同1位数"问题的通用解法

第一次在技术面试中遇到"寻找比给定数字大的最小相同1位数"问题时,我下意识地选择了暴力枚举——毕竟这是最直观的解法。但当面试官要求优化到O(1)时间复杂度时,我才意识到这类问题背后隐藏着精妙的位操作规律。这道源自信息学奥赛的经典题目,实际上是二进制版本的"下一个排列"问题,掌握其核心思想可以解决LeetCode上多个变种题目。

1. 问题本质与暴力解法剖析

给定一个正整数n,我们需要找到比n大的最小整数m,使得n和m的二进制表示中包含相同数量的1。例如n=5(二进制101),下一个符合条件的数字是6(二进制110)。

1.1 暴力枚举的实现与局限

最直接的解法是从n+1开始逐个检查每个数字的二进制1的个数:

def next_number_brute(n): count = bin(n).count('1') m = n + 1 while True: if bin(m).count('1') == count: return m m += 1

时间复杂度分析

  • 最坏情况下(如n=0b011111),需要检查2^k次(k为最低有效0位的位置)
  • 对于32位整数,最坏需要约2^30次操作
  • 实际面试中,这种解法通常会被要求优化

1.2 二进制数的结构特征

观察二进制数的变化规律,我们可以发现关键模式:

原数字:0b10011100 下一个:0b10100011

变化规律可总结为:

  1. 找到最右侧连续的1的起始位置
  2. 将该位置左侧的0变为1
  3. 将右侧所有1向右移动

2. 高效解法:位操作技巧

2.1 标准解法步骤分解

基于位操作的高效解法可分为四个核心步骤:

  1. 定位关键位:找到最右侧连续的1的起始位置(p)
  2. 设置翻转位:将p位置的1向左移动一位
  3. 重置右侧位:将p右侧所有1清零
  4. 重新分配1:在最低位补充适当数量的1

具体实现如下:

def next_number(n): # 计算最右侧连续的1的掩码 right_ones = n ^ (n + (n & -n)) # 计算需要移动的1的个数 count = (right_ones // (n & -n)) >> 1 # 构造结果 return (n + (n & -n)) | count

2.2 关键位操作原理解析

操作表达式作用
获取最低有效1位n & -n定位最右侧的1
计算右侧1的个数(n ^ (n + (n & -n))) // (n & -n) >> 1统计需要移动的1的数量
构造最终结果`(n + (n & -n))count`

提示:理解这些位操作的关键是将数字视为二进制位的动态组合,而非简单的数值

3. 与经典算法的关联:下一个排列

3.1 排列问题的二进制对应

十进制中的"下一个排列"算法与二进制版本存在惊人的相似性:

  1. 十进制下一个排列

    • 从右找到第一个下降的数字a[i]
    • 在右侧找到大于a[i]的最小数字a[j]
    • 交换a[i]和a[j]
    • 反转a[i+1:]
  2. 二进制下一个排列

    • 从右找到第一个"10"模式
    • 将"10"变为"01"
    • 将右侧所有1移到最低位

3.2 算法思想迁移对比表

操作步骤十进制排列二进制排列
查找关键位置找第一个下降位找最右侧"10"模式
交换/翻转操作交换大于关键位的最小值翻转"10"为"01"
后续处理反转右侧序列重排右侧1的位置
时间复杂度O(n)O(1)位操作

4. LeetCode实战应用

4.1 相关题目解析

掌握这个模式可以解决多个LeetCode题目:

  1. 191. Number of 1 Bits

    • 基础:计算1的个数
    • 关联:理解二进制结构
  2. 477. Total Hamming Distance

    • 进阶:统计所有位的差异
    • 应用:理解位模式变化
  3. 1879. Minimum XOR Sum of Two Arrays

    • 综合:位操作与排列组合

4.2 面试中的变种问题

实际面试中可能出现的变化形式:

  1. 前一个较小数字:找到比n小的最大数字,保持1的个数相同

    • 解法:镜像操作,找"01"变为"10"
  2. K步后的数字:求应用k次"下一个数字"操作后的结果

    • 解法:迭代应用或寻找数学规律
  3. 任意进制扩展:在三进制或其他进制下保持数字和不变

    • 解法:调整核心思想适应不同进制
# 前一个较小数字的实现 def prev_number(n): # 找到最右侧"01"模式 temp = n c0 = c1 = 0 while temp & 1 == 1: c1 += 1 temp >>= 1 while temp & 1 == 0 and temp != 0: c0 += 1 temp >>= 1 # 构造结果 mask = (1 << (c0 + c1 + 1)) - 1 return (n & ~mask) | (((1 << (c1 + 1)) - 1) << (c0 - 1))

5. 工程实践中的优化技巧

5.1 性能关键点实测

在不同编程语言中,位操作的性能差异显著:

语言操作相对耗时
C++原生位操作1x
JavaInteger.bitCount1.2x
Pythonbin().count()3.5x
JavaScript位操作2x

注意:在性能敏感场景,应优先使用位运算而非字符串操作

5.2 常见错误与调试

实现过程中容易出现的典型错误:

  1. 边界条件处理

    • 全1的情况(如0b111)
    • 0的特殊处理
  2. 位操作优先级

    • 混淆&==的优先级
    • 忘记使用括号
  3. 移位方向错误

    • 混淆左移和右移
    • 忽略符号位影响

调试技巧:

  • 使用bin()可视化中间结果
  • 对小数字手动计算验证
  • 测试2^n-1形式的特殊数字

6. 数学原理深度解析

6.1 组合数学视角

这个问题本质上是在二进制表示的所有排列中,寻找当前排列的下一个字典序排列,同时保持1的个数不变。从组合数学看:

  • 总可能性:C(w, b),其中w是位数,b是1的个数
  • 排列顺序:按二进制数值升序排列
  • 算法效率:O(1)时间找到下一个排列

6.2 信息论关联

这个问题与信息编码有密切联系:

  1. 格雷码:相邻数字仅一位不同
  2. 汉明码:错误检测与纠正
  3. 数据压缩:利用位模式规律

理解这些关联有助于设计更高效的编码方案。

7. 扩展应用场景

7.1 内存管理中的应用

操作系统内存分配器常需要找到合适大小的空闲块:

  • Buddy System使用类似算法
  • 寻找满足大小的最小块
  • 位图表示空闲状态

7.2 网络协议设计

IP地址分配和子网划分中:

  • CIDR块分配
  • 路由表优化
  • 通配符匹配

7.3 图形处理优化

在GPU编程中:

  • 位掩码操作
  • 纹理压缩
  • 并行位操作

在实际项目中遇到内存对齐问题时,这个算法曾帮我快速定位到最优的内存块分配方案。理解二进制位的排列规律,往往能在看似无关的领域找到意想不到的优化机会。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 16:55:09

不只是对齐:用 MFA 给你的 TTS 数据集自动生成 TextGrid 标注文件

不只是对齐&#xff1a;用 MFA 给你的 TTS 数据集自动生成 TextGrid 标注文件 语音合成&#xff08;TTS&#xff09;和语音识别&#xff08;ASR&#xff09;项目的核心挑战之一&#xff0c;是如何高效地将原始语音数据转化为可用于模型训练的标注文件。传统的手动标注方式不仅耗…

作者头像 李华
网站建设 2026/6/10 16:51:24

保姆级教程:用Anaconda+Labelme搞定视频目标检测标注(附清华源加速)

零基础实战&#xff1a;AnacondaLabelme视频标注全流程指南 在计算机视觉项目中&#xff0c;数据标注是模型训练前的关键步骤。对于视频数据而言&#xff0c;传统的逐帧手动标注既耗时又容易出错。本文将手把手教你使用Anaconda和Labelme工具&#xff0c;从零开始搭建视频标注环…

作者头像 李华
网站建设 2026/6/10 16:51:16

N皇后实战:用Python实现可调试的遗传算法

1. 这不是教科书&#xff0c;而是一次真实的GA项目复盘&#xff1a;从Matlab到Python的N皇后实战手记 你点开这篇文章&#xff0c;大概率不是为了背诵“遗传算法是模拟生物进化过程的优化方法”这种定义。你真正想搞清楚的是&#xff1a;当一个真实项目摆在面前——比如用遗传算…

作者头像 李华
网站建设 2026/6/10 16:47:22

恒星初始质量函数与最大熵原理的统计物理描述

1. 恒星初始质量函数的基本概念与观测特征恒星初始质量函数&#xff08;Stellar Initial Mass Function, sIMF&#xff09;是天体物理学中描述恒星形成时质量分布的核心物理量。这个概念最早由Salpeter在1955年提出&#xff0c;他发现在太阳邻域内&#xff0c;恒星质量分布遵循…

作者头像 李华
网站建设 2026/6/10 16:40:18

STM32H7的Cache到底该不该开?实测对比480MHz下代码执行效率差异

STM32H7的Cache实战指南&#xff1a;480MHz下的性能优化与数据一致性陷阱引言在嵌入式开发领域&#xff0c;性能优化永远是一个令人着迷又充满挑战的话题。当STM32H7系列微控制器将主频推向480MHz的高度时&#xff0c;一个看似简单却至关重要的问题浮出水面&#xff1a;Cache到…

作者头像 李华
网站建设 2026/6/10 16:38:12

GPT-4稀疏激活原理:揭秘1.8万亿参数仅用2%的工程逻辑

1. 项目概述&#xff1a;参数规模与稀疏激活的真相拆解“GPT-4 Has 1.8 Trillion Parameters. It Uses 2% of Them Per Token.”——这句话过去两年在技术社区反复刷屏&#xff0c;常被当作“AI算力爆炸”的佐证&#xff0c;也频繁出现在自媒体标题里&#xff0c;配图是闪烁的神…

作者头像 李华