📜  计算从1到N的所有数字中的总设置位|套装3(1)

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

计算从1到N的所有数字中的总设置位|套装3

这个主题主要是关于计算从1到N的所有数字中的总设置位的问题。对于程序员来说,这涉及到数学和编程的知识。

问题的描述

假设我们要计算从1到N的所有数字中的总设置位,其中一个数字的设置位数是指该数字中1的个数。例如,数值10的二进制表示是1010,因此它具有2个设置位。

解决方案

我们可以通过以下几种方法解决这个问题。其中,前两种方法是暴力枚举,第三种方法是一种优化算法。

方法一:暴力枚举

这个方法是最直接的方法,我们可以从1到N枚举每个数字,并计算它们中1的个数。最后将它们加起来就能得到总数。

def countSetBits1(n: int) -> int:
    def countSetBits(x: int) -> int:
        cnt = 0
        while x:
            if x & 1:
                cnt += 1
            x >>= 1
        return cnt

    res = 0
    for i in range(1, n + 1):
        res += countSetBits(i)

    return res
方法二:一位一位的统计

这种方法与第一种方法相似,只是对于每个数字,它们的1的个数不是一个一个数的统计,而是一位一位地统计。

def countSetBits2(n: int) -> int:
    res = 0
    for i in range(32):
        for j in range(1, n + 1):
            res += (j >> i) & 1

    return res
方法三:动态规划

这种方法则是一种更为优化的方法,它可以将时间复杂度降到O(logN)。

在二进制形式中,一个数字除了最高位,其它各位上都可以转化为比它低一位的数字上1的个数,例如:

  • 1100右移一位为0110,这两个数字有2位是相同的。
  • 0110右移一位为0011,这两个数字也有2位是相同的。

因此,我们可以通过这个关系推导出一个动态规划方程,可以在O(logN)的时间复杂度内求解。

def countSetBits3(n: int) -> int:
    dp = [0] * 33
    for i in range(1, 33):
        dp[i] = dp[i - 1] * 2 + (1 << (i - 1))

    res = 0
    for i in range(32, -1, -1):
        if n >= (1 << i):
            res += dp[i] + (n - (1 << i) + 1) + countSetBits3(n - (1 << i))

    return res
总结

综上所述,我们可以通过不同的方法计算从1到N的所有数字中的总设置位,其中最优解决方案是动态规划。但是,我们也应该注意到,这种问题的解决方法并不限于这些,通过增加别的方法也是完全可行的。

如果你对此有所收获,请给个Star支持一下哦:https://github.com/youngyangyang04/leetcode-master