Count Total Set Bits in First Natural Numbers in Java

2025年5月5日 | 阅读 4 分钟

问题陈述

任务是计算第一个自然数 (n) 的二进制表示中设置的位数(或 1)的总数。二进制表示是数字系统的基石。并且理解设置的位数对于故障检测、密码学和机器设计等应用至关重要。

二进制数中的设置位是数字 1。例如:

  • (3) 的二进制是 (11),包含 (2) 个设置位。
  • (5) 的二进制是 (101),包含 (2) 个设置位。

如果 (n = 5),我们计算从 (1) 到 (5) 的数字的位数组合:( 1 (1), 1 (10), 2 (11), 1 (100), 2 (101) ),结果是( 1 + 1 + 2 + 1 + 2 = 7 )

解决问题的方法

1. 朴素方法

最直接的方法是迭代从 (1) 到 (n) 的所有数字,并使用按位运算为每个数字计算设置的位数。

复杂度分析

朴素方法迭代从 (1) 到 (n) 的每个数字,并使用 Integer.bitCount() 方法为每个数字计算设置的位数。以下是详细介绍:

1. 计算每个数字的设置位数

  • Integer.bitCount() 内部操作时间复杂度为 (O(log(n))),其中 (log(n)) 是 (n) 的二进制表示中的位数。
  • 例如,对于数字 (k),位数大约为 (log2(k) + 1)。

2. 总迭代次数

  • 从 (1) 到 (n) 共有 (n) 个数字。
  • 对于每个数字,设置的位数在 (O(log(n))) 时间内计算。

因此,时间复杂度为:[O(n * log(n))]

空间复杂度

  • 朴素方法使用恒定的额外空间进行计算,因此空间复杂度为 (O(1))。

2. 优化方法

这涉及到利用二进制系统的模式来计算设置的位数,而无需迭代每个数字。二进制数字在位位置上遵循重复模式,并且数学技巧可以显著加快计算速度。

文件名:CountSetBits.java

输出

Naive Approach Total Set Bits: 25
Optimized Approach Total Set Bits: 25

解释

该代码使用两种方法计算前 (n) 个自然数的二进制表示中设置的总位数:朴素方法和优化方法。朴素方法迭代从 (1) 到 (n) 的每个数字,使用 Integer.bitCount() 为每个数字计算设置的位数,然后将它们相加,时间复杂度为 (O(n * log(n)))。

优化方法的时间复杂度为 (O(log(n))),它使用按位运算和递归来通过利用二进制数字中的模式来高效地计算设置的位数。它识别小于或等于 (n) 的最大 2 的幂((2^x)),计算到 (2^x - 1) 的所有数字中的设置位数,加上从 (2^x) 到 (n) 的数字中的设置位数,并递归处理剩余部分((n - 2^x))。基本情况确保在 (n = 0) 时递归终止。

复杂度分析

优化方法

优化方法避免了对所有数字进行迭代。相反,它利用二进制表示中的模式并递归计算总设置位数。详细分解如下:

1. 位模式

  • 该算法首先确定小于或等于 (n) 的最大 2 的幂((2^x)),这需要 (O(log(n))) 步。
  • 使用直到 2 的幂的设置位数公式,它以恒定时间 (O(1)) 计算这些模式的贡献。

2. 递归调用

  • 在计算完最大 2 的幂的贡献后,它递归计算剩余数字(即 (n - 2^x))的设置位数。
  • 在每次递归中,(n) 大约减半,导致 (O(log(n))) 次递归调用。

因此,时间复杂度为:[O(log(n))]

空间复杂度

  • 递归方法由于函数调用堆栈而具有空间开销。
  • 递归的最大深度为 (O(log(n))),因此空间复杂度为 (O(log(n)))。

结论

计算总设置位数的任务突显了二进制算术和按位运算在有效解决现实世界问题中的效用。掌握这些技术可以为程序员提供优雅且高效地处理各种计算挑战的能力。


下一个主题Java 中的弹跳数