【发布时间】:2019-12-04 08:03:17
【问题描述】:
在 Python 3.6 中,假设我有一个数字列表 L,并且我想找到给定预选长度 |S| 的所有可能的子列表 S,这样:
- 任何
S的长度必须小于L,即|S| < |L| - 任何
S只能包含出现在L中的数字 -
S中的数字不必是唯一的(它们可以重复出现) -
S中所有数字的总和应该等于预先确定的数字N
可以使用带有itertools.product 的笛卡尔积找到一个简单的解决方案。例如,假设 L 是 1 到 10(含)之间所有整数的简单列表,|S| 选择为 3。那么:
import itertools
L = range(1,11)
N = 8
Slength = 3
result = [list(seq) for seq in itertools.product(L, repeat=Slength) if sum(seq) == N]
但是,随着较大的列表L @ @或更大@ 987654338,上述方法变得极为慢。事实上,即使是L = range(1,101) 与|S|=5 和N=80,计算机也几乎死机,计算结果大约需要一个小时。
我的看法是:
- 考虑到子列表的总和应为
N - 由于迭代
itertools.product生成的可能数百万个列表以保持更少的数量,导致大量缓存未命中
所以,我的问题/挑战是:有没有一种方法可以让我以计算效率更高的方式做到这一点?除非我们谈论的是数百 GB,否则速度对我来说比内存更重要,因此挑战更多地集中在速度上,即使考虑内存效率是一个受欢迎的奖励。
【问题讨论】:
-
据我所知,这个问题存在的解决方案是 O(
N** (Slength- 1)),对于大的Slength,这将变得难以管理。 -
@Tomothy32 我猜你的意思是
|L|你在哪里写了N,对吧?在我上面的例子中,它不应该依赖于N的值。我想知道在生成产品结果时,子列表的元素必须总和为给定数字的限制是否可用于提前退出(并避免浪费内存写入) -
对不起,我的意思是
L的长度。另一件需要考虑的事情是语言。如果纯粹的速度是目标,那么您应该使用 C++、Java 等而不是 Python。无论如何,我曾经在 LeetCode 上遇到过类似的问题,我四处挖掘发现this,这可能会有所帮助。 -
你的理解贯穿所有“产品”,它随着L和S增长。它对每一个进行总和测试。如果只有少数通过并保存内存应该不是问题。
product是一个生成器。 -
所以我猜这些数字都是正整数,或者至少是 0。它应该适用于任意数字,或者它们是否以特殊方式分布?例如,对于大小 S=3 的总和 N=8,您可以在第一步中消除所有大小 > 8-3+1 的数字,因为 6+1+1 将是最大 M=6 的唯一解决方案。对于 7 没有解决方案。
标签: python performance permutation combinatorics cartesian-product