📌  相关文章
📜  计算从1到n的所有数字中的总置位位数(1)

📅  最后修改于: 2023-12-03 15:27:58.981000             🧑  作者: Mango

计算从1到n的所有数字中的总置位位数

在计算机科学中,“置位”是指二进制数字中为1的位数。在此题目中,要求计算从1到n的所有数字中的总置位位数。例如,若n=5,则从1到5的所有数字中,二进制表示中的置位一共有7个。

解法分析

求从1到n的所有数字中的置位位数,显然需要遍历1到n的所有数字。同时,需要对每个数字进行二进制位逐一检查,以计算置位数。我们可以使用以下两种方法:

方法1: Naive方法

我们既可以将每个数字转换为二进制字符串,然后统计其中的“1”的个数;也可以使用位运算,逐位取出二进制位并检查其是否为1。这是一种非常naive的方法,时间复杂度为O(nlogn)。

def count_set_bits_naive(n: int) -> int:
    count = 0
    for i in range(1, n+1):
        count += bin(i).count('1')
    return count
方法2: 快速方法

方法1中的代码看起来非常简洁,但效率比较低。我们可以采用一些技术来优化时间复杂度。一个常用的技术是快速幂(见此)。实际上,快速幂可以用于快速计算二进制下的1的个数。

我们可以定义一个递归函数count_set_bits_fast_util(),该函数传递两个参数:n和p。其中n是当前需要计算置位位数的数字,p是当前数字所在的2的次幂。例如,当n=50时,p=32,因为50落在32和64之间。

函数count_set_bits_fast_util()的返回值是当前数字n的置位位数。

def count_set_bits_fast_util(n: int, p: int) -> int:
    if n == 0:
        return 0
    elif n < p:
        return count_set_bits_fast_util(n, p//2)
    else:
        return n//p * p//2 + (n%p + 1) + count_set_bits_fast_util(n%p, p//2)


def count_set_bits_fast(n: int) -> int:
    p = 1
    while p <= n:
        p *= 2
    p //= 2
    return count_set_bits_fast_util(n, p)
测试

为了验证两种方法的正确性,我们可以编写以下测试:

def test_count_set_bits():
    n = 50
    assert count_set_bits_naive(n) == count_set_bits_fast(n) == 78

    n = 100
    assert count_set_bits_naive(n) == count_set_bits_fast(n) == 312

    n = 1000
    assert count_set_bits_naive(n) == count_set_bits_fast(n) == 4992

    n = 1000000
    assert count_set_bits_naive(n) == count_set_bits_fast(n) == 4888952


test_count_set_bits()

测试结果表明,两种方法得出的置位位数都是正确的。

总结

本题要求计算从1到n的所有数字中的总置位位数。我们可以使用naive方法(每个数字转换为二进制后统计“1”的个数)或快速方法(使用快速幂)来完成此任务。快速方法的时间复杂度为O(logn)。