【问题标题】:python: efficiency in a problem involving power seriespython:涉及幂级数问题的效率
【发布时间】:2019-03-22 22:55:44
【问题描述】:

问题定义:

这是codewars的问题。

定义一个自反向功率序列,S,为:

S(0) = 0
S(1) = 1
S(2) = 1^2 + 2 = 3
S(3) = 1^3 + 2^2 + 3 = 8
...
S(n) = 1^n + 2^(n-1) + ... + (n-1)^2 + n

实现一个接受 2 个参数(num_dig 和 ord_max)的函数,并找到序列中小于 num dig 的最小数字,而 num dig 也具有 ord_max 个数字。

如果有一个数字的位数正确,结果应该是一个数组,格式如下:

[True, smallest found term] 

[False, -1]

这些是一些例子:

n-th Term    Term Value
1              0
2              1
3              3
4              8
5              22
6              65
7              209
8              732
9              2780
10             11377
11             49863
12             232768
13             1151914
14             6018785

所以样本测试包括:

min_length_num(5, 10) == [True, 10]   # 10th term has 5 digits
min_length_num(7, 11) == [False, -1]  # no terms before 13th has 7 digits
min_length_num(7, 14) == [True, 13]   # 13th term already has 7 digits

我的方法

我创建了一个生成器,它产生幂级数 S 的所有值,直到值 n:

def seq(n):
    for i in range(n):
        s = range(i+1)
        j = i+1
        tot = 0
        while j > 0:
            for k in s:
                tot += k**j
                j -=1
            break
        yield tot

然后我检查生成器的值,然后:要么在遇到具有所需位数的第一个值时立即返回 True,否则返回 False:

def min_length_num(num_dig, ord_max): 
    i = 1
    for n in seq(ord_max):
        if len(str(n)) == num_dig:
            return [True, i]
        elif len(str(n)) > num_dig:
            break
        i +=1
    return [False, -1]

这会通过所有测试,但不会完成测试过程,因为它会超时。输入范围假设 ord_max

我对生成器不是很精通,所以也许我在那里做错了什么,或者做得不恰当。我会很感激一些帮助。谢谢。

编辑:另一种解决方案。

由于我知道 ord_max

p = [n for n in seq(1000)]

def min_length_num(num_dig, ord_max): 
    i = 1
    for k in p[:ord_max]:
        if len(str(k)) == num_dig:
            return [True, i]
        elif len(str(k)) > num_dig:
            break
        i +=1
    return [False, -1]

这更快并且解决了我的问题,但我发现它是一个非常丑陋的解决方案,更像是一个肮脏的黑客。我想要更好的东西。

【问题讨论】:

  • 使用pow 而不是**。前者使用平方取幂,这比简单乘法快一个数量级。
  • 谢谢@Rishav 我不知道。但是,我认为这并不能解决问题。
  • @Rishav:你确定它们不同吗?在 CPython 中,至少它们都使用相同的底层代码来计算 x 的 y 次方(特别是 long_pow

标签: python algorithm python-2.7 performance generator


【解决方案1】:

不是完整的解决方案,但有一些优化提示:

您不需要一次又一次地计算自然数的所有幂 - 我怀疑求幂是相当长的运算。而是存储当前权力的列表,并在每一步将power[k] 乘以k

 1  4  3       //3rd stage
 1  8  9  4    //4th stage

并根据新旧功率之差更新总和值

 S(4) = S(3) + (8-4) + (9-3) + 4 = 22

还预先计算所需位数的目标值

  powten = 10**(num_dig-1)  //1 000 000 for num_dig=7

并将总和与powten 进行比较而不转换为字符串

【讨论】:

  • 感谢您的回答,我正在编辑我的问题(我找到了一个“肮脏的解决方案”)。我喜欢你建议的第一件事,我必须考虑如何实施。
【解决方案2】:

类似于@Mbo 的建议,但不是更新具有新旧功率差异的序列,您可以简单地将现有序列乘以相应的增量,并附加新的术语编号(减一,因为第一个术语的值是0) 到序列:

def min_length_num(dig, max_term):
    seq = []
    target = pow(10, dig - 1)
    term = 1
    while term <= max_term:
        for i in range(term - 1):
            seq[i] *= i
        seq.append(term - 1)
        if sum(seq) >= target:
            return [True, term]
        term += 1
    return [False, -1]

这样:

print(min_length_num(5, 10))
print(min_length_num(7, 11))
print(min_length_num(7, 14))

会输出:

[True, 10]
[False, -1]
[True, 13]

【讨论】:

    猜你喜欢
    • 2023-03-05
    • 2014-05-29
    • 1970-01-01
    • 2013-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    相关资源
    最近更新 更多