如何在指定范围内找到一个与另一个数字相加的数字列表?

时间:2019-07-11 20:02:40

标签: python

使用Python

这里有一些要求:

我想找到一个数字列表[],

  1. 加一个数字(例如30)

  2. 位于(开始,结束)范围内(8,20)

  3. 列表中有Y个元素(例如3个)

例如:[8,10,12]

我已经尝试了下面的代码,该代码可以满足我的要求,但是它为我提供了所有组合,这些组合占用了很多内存。要选择一个,我只是随机选择了一个,但是我想将其用于范围更大的较大列表,因此效率不高。

list(combinations(list(range(8,20)),3))

2 个答案:

答案 0 :(得分:1)

您发布的代码不检查金额。

下面的代码段优化了内存使用,而不是运行时间

如果您使用的是Python 3,那么combinations已经返回了生成器。您要做的就是迭代组合。如果总和正确,则从循环中打印组合和break

from itertools import combinations

for comb in combinations(range(8, 20), 3):
    if sum(comb) == 30:
        print(comb)
        break

输出

(8, 9, 13)

或者,您可以使用filter,然后对结果调用next。这样,您可以根据需要获得任意数量的组合:

from itertools import combinations

valid_combs = filter(lambda c: sum(c) == 30, combinations(range(8, 20), 3))

print(next(valid_combs))
print(next(valid_combs))
print(next(valid_combs))

输出

(8, 9, 13)
(8, 10, 12)
(9, 10, 11)

函数和yield from(如果您使用的是Python> = 3.3)是一种更高级,更动态的解决方案:

from itertools import combinations


def get_combs(r, n, s):
    yield from filter(lambda c: sum(c) == s, combinations(r, n))


valid_combs = get_combs(range(8, 20), 3, 30)

print(next(valid_combs))
print(next(valid_combs))
print(next(valid_combs))

输出

(8, 9, 13)
(8, 10, 12)
(9, 10, 11)

答案 1 :(得分:0)

这是一个递归函数的示例,可以有效地执行此操作。

def rangeToSum(start,stop,target,count):
    if count == 0: return []
    minSum = sum(range(start,start+count-1))
    stop   = min(stop,target+1-minSum)
    if count == 1 :
        return [target] if target in range(start,stop) else [] 
    for n in reversed(range(start,stop)):
        subSum = rangeToSum(start,n,target-n,count-1)
        if subSum: return subSum+[n]
    return []

print(rangeToSum(8,20,30,3)) # [8,10,12]

它的工作方式是首先尝试最大的数字,然后调用自身以查找剩余范围内的数字,这些数字加起来即为剩余值。这将跳过无法产生目标总和的整个组合。例如尝试20次跳过包含19、18、16、15、14、13、12或11的组合。

它还考虑了第一个count-1项将产生的最小和,以进一步减小停止值。例如从8到30的3个数字达到30将使用至少17(8 + 9)的前两个数字,因此该范围的停止值可以减小到14,因为17 + 13将达到30,任何更高的值将超过30

对于大量对象,该函数在大多数情况下会很快找到解决方案,但根据参数的组合,可能还会花费很长时间。

 rangeToSum(80000,20000000,3000000,10) # 0.6 second

 # [80000, 80002, 80004, 80006, 80008, 80010, 80012, 80014, 80016, 2279928]

如果需要更快的速度,则可以尝试记忆化(例如,使用functools中的lru_cache)。