Python 返回某个数的和数的函数。py

Python 返回某个数的和数的函数。py,python,Python,我需要编写一个函数,返回通过添加列表中的数字来达到某个数字的方法数。例如: 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):

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

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()
是一个返回列表的所有子集的函数,
p
应返回达到数字n的方法数。我一直得到零输出,我不明白为什么。我很想听听你对此的意见。
提前感谢。

一个带有一个计数器的一次性解决方案,可以最大限度地减少添加

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   
但顺序很重要:
z
必须被视为此处的后代,以获得良好的计数(多亏了pm2ring)

对于大型列表,这可能非常快(
n*target
additions)

例如:

>>> enhanced_sum_with_lists(range(1,100),2500)
875274644371694133420180815

是在61毫秒内获得的。用第一种方法计算它需要宇宙的年龄

一种带有一个计数器的一次性解决方案,可最大限度地减少添加量

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   
但顺序很重要:
z
必须被视为此处的后代,以获得良好的计数(多亏了pm2ring)

对于大型列表,这可能非常快(
n*target
additions)

例如:

>>> enhanced_sum_with_lists(range(1,100),2500)
875274644371694133420180815

是在61毫秒内获得的。用第一种方法计算它需要宇宙的年龄

代码中有两个输入错误:
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

代码中有两个输入错误:
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

正如tobias_k和Faibbus提到的,您有两处输入错误:
counter1==0
,而不是
counter1=0
counter1==0
生成一个布尔对象
True
False
,但由于没有指定该表达式的结果,因此结果会被丢弃。它不会引发语法错误,因为未赋值的表达式是合法的Python

正如约翰·科尔曼(John Coleman)和B.M.提到的那样,创建完整的功率集,然后测试每个子集以确定其总和是否正确,这是不高效的。如果输入序列很小,这种方法是可以的,但是对于中等大小的序列来说,速度非常慢,如果您实际上创建了一个包含子集的列表,而不是使用生成器并在生成子集时测试子集,那么很快就会耗尽RAM

B.M.的第一个解决方案非常有效,因为它不会产生大于目标和的子集。(我不确定B.m.对基于dict的解决方案做了什么…)

但我们可以通过对总和列表进行排序来增强这种方法。这样,一旦我们检测到一个过高的总和,我们就可以打破内部的
for
循环。诚然,我们需要在外部
for
循环的每次迭代中对
sums
列表进行排序,但幸运的是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倍。

正如tobias_k和Faibbus提到的,您有两处输入错误:
counter1==0
而不是
counter1=0
counter1==0
生成一个布尔对象
True
False
,但由于没有指定该表达式的结果,因此结果会被丢弃。它不会引发语法错误,因为未赋值的表达式是合法的Python

正如约翰·科尔曼(John Coleman)和B.M.提到的那样,创建完整的功率集,然后测试每个子集以确定其总和是否正确,这是不高效的。如果输入序列很小,这种方法是可以的,但是对于中等大小的序列来说,速度非常慢,如果您实际上创建了一个包含子集的列表,而不是使用生成器并在生成子集时测试子集,那么很快就会耗尽RAM

B.M.的第一个解决方案非常有效,因为它不会产生大于目标和的子集。(我不确定B.m.对基于dict的解决方案做了什么…)

但我们可以通过对总和列表进行排序来增强这种方法。这样,一旦我们检测到一个过高的总和,我们就可以打破内部的
for
循环。诚然,我们需要在外部
for
循环的每次迭代中对
sums
列表进行排序,但幸运的是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倍。

由于
pow
是一个内置函数,您可能需要选择不同的名称。在任何情况下,如果已知所有的数字都是正数,那么检查所有的子集都是多余的。此外——除非这是家庭作业,并且要求您从头开始做所有事情,否则使用
itertools
模块是枚举子集的最简单方法。
counter1==0
应该是
counter1=0
(两次)。因打字错误而关闭。此外,可以简化为
counter2=sum(电源列表中p的sum(p)==n)
如果下面的一个答案解决了您的问题,您应该接受它(单击相应答案旁边的复选标记)。这有两件事。它让每个人都知道你的问题已经解决到令你满意的程度,并让帮助你的人相信你的帮助。有关详细说明,请参阅。由于
pow
是一个内置函数,因此您可能需要选择其他名称。在任何情况下,如果所有的数字都是正数,那么检查所有的子集都是多余的。另外——除非这是家庭作业,并且你需要使用