【问题标题】:Fastest way to find sub-lists of a fixed length, from a given list of values, whose elements sum equals a defined number从给定的值列表中找到固定长度的子列表的最快方法,其元素总和等于定义的数字
【发布时间】: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|=5N=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


【解决方案1】:

因此,给定一个输入列表和一个目标长度和总和,您需要输入列表中数字的所有排列,这样:

  1. 总和等于目标总和
  2. 长度等于目标长度

下面的代码应该更快:

# Input
input_list = range(1,101)

# Targets
target_sum = 15
target_length = 5

# Available numbers
numbers = set(input_list)

# Initialize the stack
stack = [[num] for num in numbers]

result = []

# Loop until we run out of permutations 
while stack:
    # Get a permutation from the stack
    current = stack.pop()

    # If it's too short
    if len(current) < target_length:
        # And the sum is too small
        if sum(current) < target_sum:
            # Then for each available number
            for num in numbers:
                # Append said number and put the resulting permutation back into the stack
                stack.append(current + [num])

    # If it's not too short and the sum equals the target, add to the result!
    elif sum(current) == target_sum:
        result.append(current)

print(len(result))

【讨论】:

  • 这不符合我的描述。尝试使用我的示例中的值,您会看到。我要找的不是组合。
  • 谢谢!我正在探索这个解决方案。到目前为止,我注意到它比 |S| &lt; 4 的幼稚版本更糟糕,但它似乎将 |S| &gt;= 4 的运行时间缩短了近一半,无论 |L| 的大小如何
猜你喜欢
  • 2016-09-08
  • 1970-01-01
  • 1970-01-01
  • 2023-01-07
  • 2015-09-17
  • 1970-01-01
  • 1970-01-01
  • 2014-05-26
  • 2020-06-04
相关资源
最近更新 更多