给出一个数字列表,您可以通过几种不同的方式将它们加在一起以获得总和S?
示例:
列表= [1,2]
S = 5
1)1 + 1 + 1 + 1 + 1 = 5
2)1 + 1 + 1 + 2 = 5
3)1 + 2 + 2 = 5
4)2 + 1 + 1 + 1 = 5
5)2 + 2 + 1 = 5
6)1 + 2 + 1 + 1 = 5
7)1 + 1 + 2 + 1 = 5
8)2 + 1 + 2 = 5
答案= 8
这是我尝试过的方法,但仅输出3作为答案
lst = [1, 2]
i = 1
result = 0
while i <= 5:
s_list = [sum(comb) for comb in combinations_with_replacement(lst, i)]
for val in s_list:
if val == 5:
result += 1
i+= 1
print(result)
但是,这将输出三个。我相信它会输出三个,因为它没有考虑您可以添加数字的顺序。有关如何解决此问题的任何想法。
该问题应该适用于更大的数据:但是,我给出了一个简单的例子来给出一般的想法。
答案 0 :(得分:1)
同时使用itertools.combinations_with_replacement
和permutations
:
import itertools
l = [1,2]
s = 5
res = []
for i in range(1, s+1):
for tup in itertools.combinations_with_replacement(l, i):
if sum(tup) == s:
res.extend(list(itertools.permutations(tup, i)))
res = list(set(res))
print(res)
[(1, 2, 2),
(2, 2, 1),
(1, 1, 2, 1),
(1, 2, 1, 1),
(2, 1, 1, 1),
(1, 1, 1, 2),
(2, 1, 2),
(1, 1, 1, 1, 1)]
print(len(res))
# 8
答案 1 :(得分:1)
如何使用动态编程?我相信它更容易理解并且可以轻松实现。
def cal(target, choices, record):
min_choice = min(choices)
if min_choice > target:
return False
for i in range(0, target+1):
if i == 0:
record.append(1)
elif i < min_choice:
record.append(0)
elif i == min_choice:
record.append(1)
else:
num_solution = 0
j = 0
while j < len(choices) and i-choices[j] >= 0:
num_solution += record[i-choices[j]]
j += 1
record.append(num_solution)
choices = [1, 2]
record = []
cal(5, choices, record)
print(record)
print(f"Answer:{record[-1]}")
这里的核心思想是使用一个额外的record
数组来记录可以找到多少种方法来获取当前数字,例如record[2] = 2
意味着我们可以习惯于获取2
(1+1
或2
)的总和。
我们有record[target] = sum(record[target-choices[i]])
,其中i
遍历选择。试想一下,获取sum=5
的方式必须与获取sum=4
的方式相关,依此类推。
答案 2 :(得分:1)
我们假设您的列表由[1,2,5]
组成,因此我们具有以下递归函数:
f(n,[1,2,5]) = f(n-1,[1,2,5]) + f(n-2,[1,2,5]) + f(n-5,[1,2,5])
因为如果总和中的第一个数字为1
,那么其余的您就有f(n-1,[1,2,5])
选项;如果为2
,那么其他的您有f(n-2,[1,2,5])
选项,因此在...
因此从f(1)
开始,然后逐步进行动态编程。在最坏的情况下,此解决方案是O(n^2)
,当您的列表中有O(n)
个项目时就会发生这种情况。
解决方案是这样的:
answers = []
lst = [1,2]
number = 5
def f(target):
val = 0
for i in lst: #O(lst.count())
current = target - i
if current > 0:
val += answers[current-1]
if lst.__contains__(target): #O(lst.count())
val += 1
answers.insert(target,val)
j = 1;
while j<=number: #O(n) for while loop
f(j)
j+=1
print(answers[number-1])
here是有效版本。
答案 3 :(得分:0)
您希望使用递归遍历加法每个阶段的每种可能性,并在达到等于期望值的数字时将使用的数字传回。
def find_addend_combinations(sum_value, addend_choices, base=0, history=None):
if history is None: history = []
if base == sum_value:
return tuple(history)
elif base > sum_value:
return None
else:
results = []
for v in addend_choices:
r = find_addend_combinations(sum_value, addend_choices, base + v,
history + [v])
if isinstance(r, tuple):
results.append(r)
elif isinstance(r, list):
results.extend(r)
return results
您可以将列表理解写在最后一部分,但是我认为这种方式更清楚。
答案 4 :(得分:0)
以不同顺序的元素组合被认为是等效的。例如,如果您仅谈论组合,则求和列表中的#3和#5被认为是等效的。
相反,如果排列由相同的元素以不同的顺序组成,则排列将认为这两个集合是唯一的。
要获得所需的答案,您需要将两个概念结合起来。
[ins] In [01]: def combination_generator(numbers, k, target):
...: assert k > 0, "Must be a positive number; 'k = {}".format(k)
...: assert len(numbers) > 0, "List of numbers must have at least one element"
...:
...: for candidate in (
...: {'numbers': combination, 'sum': sum(combination)}
...: for num_elements in range(1, k + 1)
...: for combination in itertools.combinations_with_replacement(numbers, num_elements)
...: ):
...: if candidate['sum'] != target:
...: continue
...: for permuted_candidate in itertools.permutations(candidate['numbers']):
...: yield permuted_candidate
...:
[ins] In [02]: {candidate for candidate in combination_generator([1, 2], 5, 5)}
Out[02]:
{(1, 1, 1, 1, 1),
(1, 1, 1, 2),
(1, 1, 2, 1),
(1, 2, 1, 1),
(1, 2, 2),
(2, 1, 1, 1),
(2, 1, 2),
(2, 2, 1)}