计算 1 到 N 之间所有整数的二进制表示中置位数的总和

给定一个整数 N (1 ≤ N ≤ 10^15),我们的任务是统计 1 到 N 之间所有整数的二进制表示中,数字 1 出现的总次数。

示例:

> 输入: N = 7

> 输出: 12

> 说明:

>

> 1 的二进制表示:001 -> 置位数 = 1

> 2 的二进制表示:010 -> 置位数 = 1

> 3 的二进制表示:011 -> 置位数 = 2

> 4 的二进制表示:100 -> 置位数 = 1

> 5 的二进制表示:101 -> 置位数 = 2

> 6 的二进制表示:110 -> 置位数 = 2

> 7 的二进制表示:111 -> 置位数 = 3

>

> 因此,1 的总个数为 1 + 1 + 2 + 1 + 2 + 2 + 3 = 12。

>

> 输入: N = 5

> 输出: 7

> 说明:

>

> 1 的二进制表示:001 -> 置位数 = 1

> 2 的二进制表示:010 -> 置位数 = 1

> 3 的二进制表示:011 -> 置位数 = 2

> 4 的二进制表示:100 -> 置位数 = 1

> 5 的二进制表示:101 -> 置位数 = 2

>

> 因此,1 的总个数为 1 + 1 + 2 + 1 + 2 = 7。

解题思路: 为了解决这个问题,我们可以遵循以下思路:

如果输入的数字 N 的形式为 2^b – 1 (例如 1, 3, 7, 15… 等),那么置位数的总数就是 b 2^(b-1)。这是因为对于 0 到 (2^b) – 1* 之间的所有数字,如果我们对列表进行补码和反转,最终会得到相同的列表(即一半的位是开启的,一半是关闭的)。

如果数字并非所有位都为 1,那么我们会找到某个位置 m 作为最左侧置位的位置。该位置上的置位数量为 n – (1 << m) + 1。剩下的置位分为两部分:

  • 处于 (m-1) 位置上的位,直到最左侧的位变为 0 的那一点,以及
  • 处于该点之下的 2^(m-1)个数字,这对应上述的闭式公式。

让我们以数字 6 为例:

0|0 0
0|0 1
0|1 0
0|1 1
-|--
1|0 0
1|0 1
1|1 0

最左侧的置位位于位置 2(位置从 0 开始计算)。如果我们将其掩码掉,剩下的是 2(最后一行右侧部分的“1 0”)。所以,第 2 个位置(左下角的框)的位数是 3(即 2 + 1)。来自 0-3 的置位(右上角的框)是 2*2^(2-1) = 4。右下角的框包含我们尚未计算的剩余位,即所有数字直到 2 的置位数(右下角框中最后一个条目的值),这部分可以通过递归计算得出。

下面是该算法的实现:

C++

INLINECODE82ca7ef3`INLINECODE5b627a3a`

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/17776.html
点赞
0.00 平均评分 (0% 分数) - 0