我有两个数字列表(A和B),A中某些元素的组合应总和为一些 B中元素的组合 在匹配组时,匹配的元素将从其列表中删除以继续,直到匹配所有组合。
例如,使用两个列表:
A = [7, 8, 12, 300, 350]
B = [3, 4, 20, 150, 500]
匹配组的总和将是:
{7: [{'A': [7], 'B': [3, 4]}],
20: [{'A': [8, 12], 'B': [20]}],
650: [{'A': [300, 350], 'B': [150, 500]}]}
我到目前为止解决这个问题的天真方法是从每个列表中得到所有可能组合的总和(pow(2,len(mylist)) - 1),在两组之间做一组交集所有组合,并按顺序删除元素,直到考虑所有元素。
有没有人知道更有效的算法来实现这一目标?扩展到每个列表的所有可能组合,然后进行集合交集会变得很大。
这是天真的方式:
def getCombos(stuff):
res = []
for L in range(1, len(stuff) + 1):
for subset in itertools.combinations(stuff, L):
res.append(subset)
return res
Acombo = getCombos(A)
Bcombo = getCombos(B)
AcomboSum = [sum(tup) for tup in Acombo]
BcomboSum = [sum(tup) for tup in Bcombo]
sumint = sorted(set(AcomboSum).intersection(set(BcomboSum)))
Arem = [a for a in A]
Brem = [b for b in B]
d = collections.defaultdict(list)
for s in sumint:
idx = sumint.index(s)
Avals = Acombo[AcomboSum.index(s)]
Bvals = Bcombo[BcomboSum.index(s)]
if set(Avals).issubset(set(Arem)) and set(Bvals).issubset(set(Brem)):
d[s].append([Avals, Bvals])
for v in Avals: Arem.pop(Arem.index(v))
for v in Bvals: Brem.pop(Brem.index(v))
else:
continue
print(d)
答案 0 :(得分:1)
按反向降序排列两个数组。
然后计算数组A中的所有总和,并按反向降序排序。
如果A [n]表示数组A中的所有元素
和B [m]表示数组B中的所有元素
和sum_A [n!]表示A中所有可能的元素总和。
和sum_A.sorted(reverse = True)表示该数组按降序排序。
创建一个新数组 B_start [n!]并将B中第一个元素的索引i存储为小于sum_A [i]。
现在对于任何sum_A [i]元素,您只需要考虑B中从B [B_start [i]]到B [m]的元素组合中的元素
注意:这仅在阵列中的所有数字都为正时才有效。