python - 生成数字序列,对于所有 k,从左到右的第 k 位数字之和为 10

标签 python sequence digits

Python 编码练习要求创建一个函数 f,使得 f(k) 是第 k 个数字,并且对于所有 k,其从左到右的第 k 个数字之和为 10。例如,5、19、28、37 是序列中的前几个数字。

我使用此函数显式检查数字“n”是否满足属性:

def check(n):

    #even digit length
    if len(str(n)) % 2 == 0:

        #looping over positions and checking if sum is 10
        for i in range(1,int(len(str(n))/2) + 1):

            if int(str(n)[i-1]) + int(str(n)[-i]) != 10:

                return False

    #odd digit length
    else:

        #checking middle digit first
        if int(str(n)[int(len(str(n))/2)])*2 != 10:

            return False

        else:
            #looping over posotions and checking if sum is 10
            for i in range(1,int(len(str(n))/2) + 1):

                if int(str(n)[i-1]) + int(str(n)[-i]) != 10:

                    return False

    return True

然后我循环所有数字以生成序列:

for i in range(1, 10**9):

    if check(i):
        print(i)

然而,练习需要一个函数 f(i) 在 10 秒内返回第 i 个这样的数字。显然,我的需要更长的时间,因为它生成数字“i”之前的整个序列来计算它。是否可以创建一个不必计算所有先前数字的函数?

最佳答案

测试每个自然数是一个糟糕的方法。只有一小部分自然数具有这种性质,并且随着数字的增加,这个比例会迅速减少。在我的机器上,下面的简单 Python 程序花费了 3 秒多的时间来查找第 1,000 个数字 (2,195,198),并花费了 26 秒多的时间来查找第 2,000 个数字 (15,519,559)。

# Slow algorithm, only shown for illustration purposes

# '1': '9', '2': '8', etc.
compl = {str(i): str(10-i) for i in range(1, 10)}

def is_good(n):
    # Does n have the property
    s = str(n)
    for i in range((len(s)+1)//2):
        if s[i] != compl.get(s[-i-1]):
            return False
    return True

# How many numbers to find before stopping
ct = 2 * 10**3

n = 5
while True:
    if is_good(n):
        ct -= 1
        if not ct:
            print(n)
            break
    n += 1

显然,需要一种更高效的算法。

我们可以循环数字字符串的长度,并在其中按数字顺序生成具有属性的数字。伪代码算法简述:

for length in [1 to open-ended]:
    if length is even, middle is '', else '5'
    half-len = floor(length / 2)
    for left in (all 1) to (all 9), half-len, without any 0 digits:
        right = 10's complement of left, reversed
        whole-number = left + middle + right

现在,请注意,每个长度的数字计数很容易计算:

Length    First    Last     Count
1         5        5        1
2         19       91       9
3         159      951      9
4         1199     9911     81
5         11599    99511    81

一般来说,如果左半部分有 n 位数字,则计数为 9**n

因此,我们可以简单地迭代数字计数,计算存在多少个解决方案,而无需计算它们,直到我们到达包含所需答案的队列。然后,再次计算我们想要的数字应该相对简单,而不必迭代每种可能性。

上面的草图应该会产生一些想法。我写完后就可以遵循的代码。

代码:

def find_nth_number(n):
    # First, skip cohorts until we reach the one with the answer
    digits = 1
    while True:
        half_len = digits // 2
        cohort_size = 9 ** half_len
        if cohort_size >= n:
            break
        n -= cohort_size
        digits += 1

    # Next, find correct number within cohort

    # Convert n to base 9, reversed
    base9 = []
    # Adjust n so first number is zero
    n -= 1
    while n:
        n, r = divmod(n, 9)
        base9.append(r)
    # Add zeros to get correct length
    base9.extend([0] * (half_len - len(base9)))
    # Construct number
    left = [i+1 for i in base9[::-1]]
    mid = [5] * (digits % 2)
    right = [9-i for i in base9]
    return ''.join(str(n) for n in left + mid + right)

n = 2 * 10**3

print(find_nth_number(n))

关于python - 生成数字序列,对于所有 k,从左到右的第 k 位数字之和为 10,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57135942/

相关文章:

c++ - C++ 11的序列压缩函数?

数字的 C++ 精度和 fstream 的截断

matlab - 四舍五入到 n 位有效数字

python - 在 while 循环中使用 'not in' 和 'or'

python - reshape Pandas 数据框

sql-server - T-SQL 识别中断的日期序列中的差距

xslt - 如何在 XSLT 中声明一个序列?

c++ - 设置小数点后的位数

python - 如何在 Tensorflow Object Detection API v2 中同时训练和评估

python - 元素树xml