【问题标题】:Find the Nth number that contains at least one even digit找到包含至少一个偶数的第 N 个数字
【发布时间】:2021-04-01 14:48:16
【问题描述】:

我正在关注这个挑战:

找到第 Nth 个至少包含一个偶数位的数字。

N 值的示例结果:

N result
1 2
2 4
3 6
4 8
5 10
6 12
7 14
8 16
9 18
10 20
11 21
12 22
13 23
14 24
... ...

N 是自然数,0 N 18

程序必须在 1 秒内返回正确的结果。

这是我的尝试:

N = 14
number = 0

while N > 0:
    number += 1

    if '0' in str(number) or '2' in str(number) or '4' in str(number) or '6' in str(number) or '8' in str(number):
        N -= 1

print(number) // 24

此代码正在运行,但如果 N 为 1018 甚至 1016,则无法在 1 秒内解决此任务。当 N 为大整数时,while 循环的迭代次数过多...

我怎样才能加快这个程序?

【问题讨论】:

  • 作为一个练习,看看你是否能想出一个规则,告诉你对于一个整数k0 < N <= 10**k 中有多少个N 也满足条件。然后看看你是否可以使用这些信息来加速代码。您可能可以走得更远。

标签: python algorithm


【解决方案1】:

你可以用递归解决这个问题。

一个重要的观察是,低于某个限制的“好”数字的计数,即具有至少一个 偶数 位的数字,等于:

  • 数字本身(从 0 开始计算所有数字)
  • 排除所有仅由奇数组成的数字
  • 不包括零

仅由 10 次幂以下的奇数组成的数字的计数是:

  • 5 + 5² + 5³ + ... + 5k,其中 k 是幂,等于 (5k+1 sup>-1)/4-1

仅由 10 次方到 10 次方两倍之间的奇数组成的数字计数(因此这些数字具有固定的位数,始终从 1 开始)是:

  • 5k

当然,如果最高有效位是 2(或另一个偶数),则奇数的计数为零。

因此,您可以使用这些成分构建解决方案:

def count_even(digit, num_zeroes):
    # The arguments encode a number that only has one non-zero digit, the first:
    # - digit: the most significant digit (1..9)
    # - num_zeroes: the count of trailing zeroes
    # Returns the count of numbers less than this encoded number that have at
    #   least one even digit
    return (10**num_zeroes * digit  # count all numbers 
        # exclude numbers with fewer digits and only odd digits:
        - ((5**(num_zeroes+1)-1)//4-1)   
        # exclude numbers with same digit count and only odd digits, 
        #  but with first digit less than given digit,
        - 5**num_zeroes * (digit//2)
        # ...and exclude 0
        - 1
    )

# The main algorithm
def get_nth_with_even_digit(n):
    # Base cases
    if n < 10: 
        return n * 2  # 2, 4, 6, ..., 18
    if n < 20:
        return 10 + n  # 20 - 29

    # Use recursion to build on previous results:
    num_zeroes = 1
    while True:
        diff = count_even(3, num_zeroes) - count_even(1, num_zeroes)
        num_zeroes += 1
        power = 10**num_zeroes
        limit = 1 + count_even(2, num_zeroes)
        if n < limit:
            return power//5 + get_nth_with_even_digit(n - diff)
        if n < limit + power:
            return n + power//5 + get_nth_with_even_digit(limit - diff) - limit

在测试代码时,我使用了类似您自己的蛮力实现,并将结果与​​上述函数的结果进行了比较:

# Testing code - will keep running until a difference is found with the brute force method
def brute():
    for i in range(10000000000):
        if any(d in "02468" for d in str(i)):
            yield i

for n, expected in enumerate(brute()):
    got = get_nth_with_even_digit(n)
    assert got == expected, "{}: got {}, expected {}".format(n, got, expected)
    print(n, expected)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-10
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 2014-10-25
    • 1970-01-01
    • 2022-01-13
    相关资源
    最近更新 更多