我很想向后做,我不确定是否允许(请参阅我的评论。)
因此,与其逐个消除值,不如找到总和在该范围内的最小子列表!
有一个问题——子集和问题是 np 完全的,所以这种方法也是。(想象一下你的范围是 0 的情况,这是同样的问题。)
有一个已知的算法可以在 O(2 N/2 )中解决这个问题。我将模拟一些 Python 代码,但与此同时,维基百科页面应该会有所帮助。由于您想在一个范围内找到最少的列表,因此显然需要进行一些修改。
本质上,您将列表分成两个长度为 N/2 的任意子列表(其中您的列表有 N 个元素。)然后在每个列表中生成所有子集,并计算它们的总和。(在这里,我会将子集及其总和存储在字典中,这样您就知道还剩下哪些数字。由于您只想找到最小的数字,因此我还将消除所有与较小的子集具有相同总和的子集。)对这些列表进行排序,然后向前和向后遍历,直到找到所有适合该范围的总和。最后,找出哪个包含最少的元素,你就可以开始了!
如果只要最终列表在范围内,您就可以进行违反规则的消除,请查看此问题
编辑:这里有一些 Python。这是:
未经测试
Python,所以不是特别快
显然不是最优的
急需重构
但我认为作为一个总体思路,您将能够获得最快的算法。我很想看到一个更快的概念!
>>> from itertools import combinations, chain
>>>
>>> available = [-10, -5, -2, 7, 9, 15]
>>> target = (10, 18)
>>>
>>>
>>>
>>> def powerset(iterable): # from https://stackoverflow.com/questions/374626/how-can-i-find-all-the-subsets-of-a-set-with-exactly-n-elements
... xs = list(iterable)
... # note we return an iterator rather than a list
... return chain.from_iterable(combinations(xs, n) for n in range(len(xs)+1))
...
>>>
>>> def getMinList(available, target):
... middleIndex = len(available)/2
... l1 = available[:middleIndex]
... l2 = available[middleIndex:]
... dict1 = {}
... dict2 = {}
... for subset in powerset(l1): # reverse so only the smallest subsets are used.
... total = sum(subset)
... if total not in dict1:
... dict1[total] = subset
... for subset in powerset(l2):
... total = sum(subset)
... if total not in dict2:
... dict2[total] = subset
... sortedDict1 = sorted(dict1.iteritems())
... sortedDict2 = sorted(dict2.iteritems())
... resultList = ()
... minValues = middleIndex * 2
... for k1, v1 in sortedDict1:
... for k2, v2 in reversed(sortedDict2):
... sumOfSubsets = k1 + k2
... if sumOfSubsets <= target[1] and sumOfSubsets >= target[0]:
... newTuple = v1 + v2
... lenNewTuple = len(newTuple)
... if (lenNewTuple) < minValues:
... resultList = ((sumOfSubsets, newTuple))
... minValues = lenNewTuple
... return resultList
...
>>> getMinList(available, target)
(15, (15,))
>>>
>>> target = (10, 10)
>>>
>>> getMinList(available, target)
(10, (-5, 15))
>>>
>>> target = (19, 22)
>>>
>>> getMinList(available, target)
(22, (7, 15))