返回某个number.py的总和数的函数

时间:2017-01-28 13:37:12

标签: python

我需要编写一个函数,通过添加列表的数字来返回达到某个数字的方式的数量。例如:

ans = 5

我写的代码是:

print(p([3,5,8,9,11,12,20], 20))
should return:5

def pow(lis): power = [[]] for lst in lis: for po in power: power = power + [list(po)+[lst]] return power def p(lst, n): counter1 = 0 counter2 = 0 power_list = pow(lst) print(power_list) for p in power_list: for j in p: counter1 += j if counter1 == n: counter2 += 1 counter1 == 0 else: counter1 == 0 return counter2 是一个函数,它返回列表的所有子集,pow()应该返回到达数字n的方式的数量。我一直得到零输出,我不明白为什么。我很想听听你的意见。 提前谢谢。

4 个答案:

答案 0 :(得分:1)

具有一个计数器的单程解决方案,可最大限度地减少添加。

def one_pass_sum(L,target):
   sums = [0]
   cnt = 0
   for x in L:
       for y in sums[:]: 
           z = x+y
           if z <= target : 
                sums.append(z)
                if z == target : cnt += 1
   return cnt   

这种情况如果n=len(L),则通过计算所有总和,对2^n的{​​{1}}次增加少于n/2 * 2^n次。

编辑:

更有效的解决方案,只是计算方法。我们的想法是,如果kz-x种方法,k出现z时,x还有def enhanced_sum_with_lists(L,target): cnt=[1]+[0]*target # 1 way to make 0 for x in L: for z in range(target,x-1,-1): # [target, ..., x+1, x] cnt[z] += cnt[z-x] return cnt[target] 种方式。

z

但是顺序很重要:n*target必须在这里被视为后代,才能获得好计数(感谢PM 2Ring)。

对于大型列表,这可能非常快(>>> enhanced_sum_with_lists(range(1,100),2500) 875274644371694133420180815 次添加)。

例如:

asp-for

在61毫秒内获得。它将花费宇宙的年龄来通过第一种方法来计算它。

答案 1 :(得分:1)

您的代码中有两个拼写错误:counter1 == 0是一个布尔值,它不会重置任何内容。

此版本应该有效:

def p(lst, n):
    counter2 = 0
    power_list = pow(lst)       
    for p in power_list:
        counter1 = 0 #reset the counter for every new subset
        for j in p:
            counter1 += j
        if counter1 == n:
            counter2 += 1
    return counter2

答案 2 :(得分:1)

正如tobias_k和Faibbus所提到的,在两个地方你有一个拼写错误:counter1 == 0而不是counter1 = 0counter1 == 0生成一个TrueFalse的布尔对象,但由于您没有分配该表达式的结果,结果将被丢弃。它没有引发SyntaxError,因为没有分配的表达式是合法的Python。

正如John Coleman和B. M.提到的那样,创建完整的powerset然后测试每个子集以查看它是否具有正确的总和效率不高。如果输入序列很小,这种方法是可以的,但即使是中等大小的序列,它也非常慢,如果你实际创建一个包含子集的列表而不是使用生成器并测试它们的子集。让你很快就用光了。

B中。 M。的第一个解决方案非常有效,因为它不会产生大于目标总和的子集。 (我不确定B. M.正在使用基于dict的解决方案......)。

但我们可以通过对总和列表进行排序来增强该方法。这样,一旦我们检测到过高的总和,我们就可以突破内部for循环。确实,我们需要在外部sums循环的每次迭代中对for列表进行排序,但幸运的是,Python的TimSort非常有效,并且它已经过优化以处理列表排序它包含已排序的子序列,因此它非常适合此应用程序。

def subset_sums(seq, goal):
    sums = [0]
    for x in seq:
        subgoal = goal - x
        temp = []
        for y in sums:
            if y > subgoal:
                break
            temp.append(y + x)
        sums.extend(temp)
        sums.sort()
    return sum(1 for y in sums if y == goal)

# test

lst = [3, 5, 8, 9, 11, 12, 20]
total = 20
print(subset_sums(lst, total))

lst = range(1, 41)
total = 70
print(subset_sums(lst, total))

<强>输出

5
28188

使用lst = range(1, 41)total = 70,此代码比B.M.快3倍。列出版本。

答案 3 :(得分:0)

from itertools import chain, combinations

def powerset_generator(i):
    for subset in chain.from_iterable(combinations(i, r) for r in range(len(i)+1)):
        yield set(subset)

def count_sum(s, cnt):
    return sum(1 for i in powerset_generator(s) if sum(k for k in i) == cnt)

print(count_sum(set([3,5,8,9,11,12,20]), 20))