该功能的目标和条件如下:
目标sum_dig
sum_dig
sum_dig
条件
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]
P.S。对不起,如果有任何问题,我是新来的代码,请让我知道^^ Thx提前!
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))]
答案 0 :(得分:0)
这是另一种强大技术branch-and-bound的例子。一般的想法是,如果我们将数字中的第一个数字修改为i
,我们可以将此任务减少到find_all(sum_digi-i, digits-1)
。此外,我们可以对搜索空间进行大量修剪,因为我们知道可行sum_digi
属于[digits*min_digit, 9*digits]
,其中min_digit
是前缀中的最大数字(数字按递增顺序排列)。其余的只是结合最小和最大:
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)