📌  相关文章
📜  计算不超过N的数字,其中至少包含一个重复的数字(1)

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

计算不超过N的数字,其中至少包含一个重复的数字

本篇文章介绍如何编写一个函数,计算不超过N的数字中,至少包含一个重复的数字的数字个数。例如,对于N=20,答案是9,因为从1到20中,有9个数至少包含一个重复的数字。

实现思路

本题可以通过枚举所有数字,然后检查每个数字是否至少包含一个重复的数字来解决。但是这种解法的时间复杂度是O(NlogN),因为每个数字的位数最多是logN,我们需要对每个数字进行O(logN)时间的检查。本文介绍的是一种时间复杂度为O(logN)的解法。

我们可以先考虑如何计算1到N之间,有多少个数字不包含重复的数字。

假设有一个长度为len的数字N,我们分别考虑数字的每一位。对于每一位,我们可以用高位和低位的方式把N分成两个部分:

  • 高位:从最高位到当前位的下一位,例如对于数字12345,当前位是百位,那么高位就是12。
  • 低位:从当前位到最低位,例如对于数字12345,当前位是百位,那么低位就是345。

假设当前位的数字是x,那么有以下三种情况:

  • 如果x==0,那么当前位可以是1到9中的任意一个数字,所以有9个选择。如果高位中都没有数字,那么低位可以是1到9中的任意一个数字,所以有9^(len-1)种选择。如果高位中有数字,那么低位可以是0到9中的任意一个数字,所以有10^(len-2)种选择。综上,当前位对答案的贡献是9*(9^(len-1)+10^(len-2))。
  • 如果x==1,那么当前位可以是0到9中的任意一个数字,所以有1+9种选择。如果高位中都没有数字,那么低位可以是1到9中的任意一个数字,所以有9^(len-1)种选择。如果高位中有数字,那么低位可以是0到9中的任意一个数字,所以有10^(len-2)种选择。综上,当前位对答案的贡献是1*(9^(len-1)+10^(len-2))+9*(9^(len-1)+10^(len-2))。
  • 如果x>=2,那么当前位可以是0到9中的任意一个数字,所以有10种选择。如果高位中都没有数字,那么低位可以是1到9中的任意一个数字,所以有9^(len-1)种选择。如果高位中有数字,那么低位可以是0到9中的任意一个数字,所以有10^(len-2)种选择。综上,当前位对答案的贡献是10*(9^(len-1)+10^(len-2))。

最终的答案就是将1到N的所有数字的贡献相加。具体实现可以用递归的方式按位计算。

当然,如果我们要计算至少包含一个重复的数字的数字个数,只需要使用总数减去不包含任何重复数字的数字个数即可。

代码实现

下面是用Python实现的具体代码片段。需要注意的是,代码中使用的是递归方式按位计算,而不是循环方式。这是因为循环方式需要手动计算出每一位的值,而递归方式则便于直接计算当前位的贡献,从而简化了代码。同时,为了提高效率,代码中使用了记忆化(即缓存计算结果)的方式。

class Solution:
    def countNumbersWithDup(self, n: int) -> int:
        self.cache = {}
        return n - self.countNumbersWithoutDup(n)

    def countNumbersWithoutDup(self, n: int) -> int:
        if n == 0:
            return 0
        if n < 10:
            return n
        if n in self.cache:
            return self.cache[n]

        high = int(str(n)[0])
        low = int(str(n)[1:])
        len_high = len(str(high))
        len_low = len(str(low))

        res = 0
        # 计算高位中没有数字的情况
        res += 9 * self.countNumbersWithoutDup(10 ** (len(n) - 1) - 1)
        # 计算高位中有数字的情况
        if high == 1:
            res += 1 * (low + 1) + 9 * (self.countNumbersWithoutDup(10 ** (len(n) - 2) - 1))
        elif high >= 2:
            res += 10 * self.countNumbersWithoutDup(10 ** (len(n) - 2) - 1)
        # 记录计算结果
        self.cache[n] = res
        return res
总结

本文介绍了一种计算不超过N的数字中至少包含一个重复的数字的数字个数的方法。使用该方法可以在O(logN)的时间复杂度内解决该问题,比暴力枚举的O(NlogN)时间复杂度更快。同时,本文还介绍了实现思路和具体代码,希望可以帮助读者理解和实现该算法。