我对如何解决这个问题感到有些困惑。我知道我想做什么,但无法解决如何从逻辑上解决这个问题。 说我有一个清单:
numlist = [10,4]
我在另一个列表中有以下值:
datalist = [10,5,4,2,1]
如何仅使用numlist
中的数字来细分datalist
中的数字?
答案的一个例子是:
10, 4 10, 2,2 10, 2,1,1 10, 1,1,1,1 5,5, 4 5,5, 2,2
......等等。
我理解如何模糊地做到这一点。为列表中的每个条目创建一个for循环,并比较它是否可以被datalist分割,如果是,则打印结果。我想我需要递归,这是我无法理解的地方。
这是我到目前为止的代码(我有一些用于故障排除的打印语句):
def variableRecursion(self, solutionList):
#solution list contrains ['red', 2, 'green', 1] which means 2 reds(value 4) and 1 green(value 2)
#adding fake lookup list for now, in real code, I can use real data because I am reversing the order
list = [('red', 4), ('green', 2), ('blue', 1) ]
for x1, x2 in zip(solutionList[::2], solutionList[1::2]):
for x in list:
for y1, y2 in zip(x[::2], x[1::2]):
#print x1, x2
keyName = x1
keyShares = x2
keyValue = lookup.get_value(x1)
if ((keyValue%y2) == 0) and (keyValue != y2):
tempList = []
#print 'You can break ', keyName, keyValue, ' with ', y1, y2, ' exactly ', keyValue/x2, ' times.'
#newKeyShares = keyShares - 1
for a1, a2 in zip(solutionList[::2], solutionList[1::2]):
#print a1, a2
print 'You can break ', keyName, keyValue, ' with ', y1, y2, ' exactly ', keyValue/y2, ' times.'
newKeyShares = keyShares - 1
print 'there is a match', a1, a2, ' but we will change the shares to ', newKeyShares
print a1
if (a1 == keyName):
print 'a'
tempList.append([(keyName), (newKeyShares)])
elif (a1 == y1):
print 'b'
tempList.append([(y1), (a2+keyValue/y2)])
else:
print 'c'
try:
tempList.append([(y1), (a2+keyValue/y2)])
except e:
tempList.append([(a1), (a2)])
print tempList
appendList.appendList(tempList)
tempList = []
#exit()
#print solutionList
答案 0 :(得分:3)
这个问题与欧拉项目的Problem 31非常相似:“使用任意数量的硬币可以用多少种不同的方式进行2英镑?”。仅在您的示例中,您要求枚举所有可以添加数字以获得10和4的方法。
解决问题的最佳方法是首先尝试分解一个数字。让我们看看五个可能的分手,使用数字[5,4,2,1]:
[5]
[4,1]
[2,2,1]
[2,1,1,1]
[1,1,1,1,1]
以下python代码将为您提供这些组合的列表:
def possibleSplits(value,validIncrements):
ret = []
for increment in validIncrements:
if increment > value:
continue
if increment == value:
ret.append([increment])
continue
if increment < value:
remainder = value - increment
toAdd = possibleSplits(remainder, validIncrements)
for a in toAdd:
ret.append([increment] + a)
return ret
此代码假定其他相同答案的不同排序应视为不同。例如,当您拆分时,[4,1]和[1,4]都将显示为解决方案。如果您愿意,可以将其约束为仅具有数字排序的答案(因此[1,4]出现但不是[4,1])
def orderedPossibleSplits(value, validIncrements):
ret = []
splits = possibleSplits(value, validIncrements)
for value in splits:
value.sort()
if value not in ret:
ret.append(value)
return ret
现在你可以使用它来查找10的可能拆分和4的可能拆分,并将它们组合起来:
increments = [10, 5, 4, 2, 1]
tenSplits = orderedPossibleSplits(10, increments)
fourSplits = orderedPossibleSplits(4, increments)
results = []
for tenSplit in tenSplits:
for fourSplit in fourSplits:
results.append(tenSplit + fourSplit)
编辑:如评论中所述,调用值为100的possibleSplits非常慢 - 超过十分钟并计数。发生这种情况的原因是因为possibleSplits(100)将递归调用possibleSplits(99),possibleSplits(98)和possibleSplits(96),每个都调用自己的三个可能的Splits,依此类推。我们可以用datalist [1,2,4]和大N来估计可能的Splits(N)的处理时间
processingTime(N)= C + processingTime(N-1)+ processingTime(N-2)+ processingTime(N-4)
持续一段时间C.
所以可能的Splits的相对时间是
N 1 | 2 | 3 | 4 | 5 ... 20 ... 98 | 99 | 100
Time 1 | 1 | 1 | 4 | 7 ... 69748 ... 30633138046209681029984497 | 56343125079040471808818753 | 103631163705253975385349220
假设可能的Splits(5)需要7 ns,可能的Splits(100)需要大约3 * 10 ^ 9年。对于大多数实用程序来说,这可能是一个不合适的长时间。但是,我们可以通过利用记忆来减少这段时间。如果我们保存先前计算的调用的结果,我们可以获得线性时间复杂度,将可能的Splits(100)减少到100 ns。
评论还指出,orderedPossibleSplits(100)的预期价值约有700个元素。因此,possibleSplits(100)将具有更多的元素,因此即使使用memoization它也是不切实际的。相反,我们将丢弃它并重写orderedPossibleSplits以使用memoization,并且不依赖于possibleSplits。
#sorts each element of seq and returns it
def orderedInnerLists(seq):
return map(sorted, seq)
#returns a copy of seq with duplicates removed
def removeDuplicates(seq):
ret = []
for value in seq:
if value not in ret:
ret.append(value)
return ret
memoizedResults = {}
def orderedPossibleSplits(value,validIncrements):
memoizeKey = (value, tuple(validIncrements))
if memoizeKey in memoizedResults:
return memoizedResults[memoizeKey]
ret = []
for increment in validIncrements:
if increment > value:
continue
if increment == value:
ret.append([increment])
continue
if increment < value:
remainder = value - increment
toAdd = orderedPossibleSplits(remainder, validIncrements)
for a in toAdd:
ret.append([increment] + a)
memoizeValue = removeDuplicates(orderedInnerLists(ret))
memoizedResults[memoizeKey] = memoizeValue
return memoizeValue
在我的机器上,orderedPossibleSplits(100,[1,2,4])大约需要10秒钟 - 比我们最初的30亿年运行时间大大改善。