📌  相关文章
📜  范围内的数字计数,其中数字包含的位数不超过K个非零数字(1)

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

以范围内的数字计数,其中数字包含的位数不超过K个非零数字

这个问题可以分为两个部分:(1)如何生成位数不超过K个非零数字的数字;(2)如何计数该范围内的数字数量。

生成位数不超过K个非零数字的数字

一种简单的方法是使用递归回溯。我们可以从第一位开始,遍历从1到9的所有数字。如果已经生成了j位数字,那么下一位数字可以是0到9中除了0以外的任意一个数字。如果当前已经生成了k个非零数字,那么下一位数字只能是0。当生成的数字的位数达到k位时,递归终止并将该数字加入到结果集中。

def generate_numbers(n: int, k: int) -> List[int]:
    result = []

    def dfs(num: int, count: int):
        if len(str(num)) > k or count > k:
            return
        if num >= n:
            return
        result.append(num)
        for i in range(0 if num else 1, 10):
            non_zero = count + (i != 0)
            dfs(num * 10 + i, non_zero)
    
    dfs(0, 0)
    return result

其中,参数n表示范围的上界,k表示数字中最多可以有k个非零数字。返回一个列表,其中包含所有符合要求的数字。

计数该范围内的数字数量

我们可以使用二分答案的思想得到范围内符合要求的数字数量。假设我们已经得到了所有符合要求的数字,那么数量就是所有数字中小于等于上界n的数字个数减去所有数字中小于下界0的数字个数。由于两个数字的差可能很大,我们可以通过对数字位数的差分别计算数量并相加,然后使用前缀和计算范围内的数量。

def count_numbers(n: int, k: int) -> int:
    numbers = generate_numbers(n, k)
    counts = [0] * (k + 1)
    total_count = 0
    for i in range(1, k + 1):
        counts[i] = counts[i - 1] * 9 + 10 ** (i - 1)
        total_count += counts[i]
    
    def calc_count(x: int) -> int:
        if x == 0:
            return 0
        digits = list(map(int, str(x)))
        prefix_count = 0
        non_zero_count = 0
        for i, digit in enumerate(digits):
            num_count = 0
            for j in range(0 if i else 1, digit):
                if non_zero_count + (j != 0) <= k:
                    num_count += 1
            prefix_count += num_count * (counts[len(digits) - i - 1] + (non_zero_count + (digit != 0)))
            if digit != 0:
                prefix_count += calc_count(int(''.join(map(str, digits[i + 1:]))))
                non_zero_count += 1
            if non_zero_count > k:
                break
        return prefix_count
    
    return calc_count(n) - calc_count(0)

其中,参数n表示范围的上界,k表示数字中最多可以有k个非零数字。返回一个整数,表示该范围内所有符合要求的数字数量。

总结

本文介绍了如何计算范围内的数字数量,其中数字包含的位数不超过K个非零数字。我们可以使用递归回溯的方法生成所有符合要求的数字,然后使用二分答案的方法计算数量,并使用前缀和优化时间复杂度。