【问题标题】:How can i enhance the performance of following code?如何提高以下代码的性能?
【发布时间】:2018-01-16 04:07:56
【问题描述】:

此功能的目标和条件如下:

目标
1. 所有这些数字的总和是数字的总和 == sum_dig
2. 自己的数字之和的最小值 == sum_dig
3.自身digi之和的最大数 == sum_dig 条件
4. 数字必须按升序排列
5. 位数 == digs


示例
find_all(10, 3) 应该返回 [8, 118, 334]
find_all(27, 3) 应该返回 [1, 999, 999]
find_all(84, 4) 应该返回 []
find_all(35, 6) 应该返回 [123, 116999, 566666]

附言抱歉,我是新手,如果有任何问题,请告诉我^^ 提前谢谢!

def find_all(sum_dig, digs):
    ls = set(n for n in set(''.join(sorted(str(i))) for i in range(int('1'*digs),int('9'*digs)+1) if '0' not in str(i)) if sum(int(i) for i in n) == sum_dig)
    if len(ls) ==0:
        return []
    return [len(ls),int(min(ls)),int(max(ls))]

可读版本

def find_all(sum_dig, digs):
    #find int in increasing order within range
    ls = set(''.join(sorted(str(i))) for i in range(int('1'*digs),int('9'*digs)+1))
    #find sum of it's digi == sum_dig within min. list 
    ls = set(n for n in ls if '0' not in n and sum(int(i) for i in n) == sum_dig)
    if len(ls) ==0:
        return []
    return [len(ls),int(min(ls)),int(max(ls))]

【问题讨论】:

  • 您在这里所做的是暴力搜索,其复杂性呈指数级增长(即执行时间增长得非常快)。使用动态规划可以更有效地解决这个特定问题
  • 首先是让代码可读。格式化,使其无需滚动即可阅读。带有 3 个 for 子句的生成器表达式很难阅读。
  • 谢谢 Marat,对不起,我还在学习,你能解释一下吗?百万谢谢!
  • 谢谢特里,因为目标是最大化性能,所以我编写了这样的代码。我发现这有点快,然后在测试后写得更有结构。无论如何,我添加了可读版本以便于阅读^^

标签: python algorithm


【解决方案1】:

这是branch-and-bound 的示例,这是另一种强大的技术。一般的想法是,如果我们将数字中的第一个数字固定为i,我们可以将此任务简化为find_all(sum_digi-i, digits-1)。此外,我们可以大量修剪搜索空间,因为我们知道可行的sum_digi 属于[digits*min_digit, 9*digits],其中min_digit 是前缀中的最大数字(数字按升序排列)。剩下的就是结合 min 和 max:

def find_all(sum_digi, digits, min_digit=1):
     grand_total = 0
     super_min = 10**digits-1
     super_max = 0
     if digits == 1:
         if min_digit <= sum_digi <= 9:
             return 1, sum_digi, sum_digi
     elif digits > 1: 
         for i in range(min_digit, 10):
             if (digits-1)* min_digit <= sum_digi -i <= 9*(digits-1):
                 total, n_min, n_max = find_all(sum_digi - i, digits-1, i)
                 if total:
                     grand_total += total
                     super_min = min(super_min, 10**(digits-1)*i+n_min)
                     super_max = max(super_max, 10**(digits-1)*i+n_max)
     return grand_total, super_min, super_max

性能:

In [4]: %%time
   ...: find_all(100, 20)
   ...: 
CPU times: user 380 ms, sys: 12 ms, total: 392 ms
Wall time: 384 ms
Out[4]: (61731, 11111111119999999999L, 55555555555555555555L)

【讨论】:

  • 百万感谢马拉,让我看看我能理解^^。美好的一天~
  • 我认为您可以使用记忆来加快少量输入。
  • @PetarPetrovic 这就是动态编程基本上会做的事情,建立一个已解决子任务的表。 DP解决方案我懒得写代码
猜你喜欢
  • 2016-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多