给出一个范围列表,找出这些范围的总和为k的所有组合

2024-10-04 11:23:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我有34个数字范围。 例如:

x1 = {25,35}
x2 = {28,36}
x3 = {15,20}
.
.
x34 = {28,37}

我必须找到所有的组合,这样我从每个范围中选择一个数字,所有这34个数字加起来就是k

例如:

let k = 600

so from x1 - we pick 26

from x2 - we pick 29

.

.

and from x34 we pick 16.

Then, x1 + x2 + x3 + x4 + … + x34 = 600.

我想要所有这些组合

用某种算法是可行的吗

我想用python实现这一点


Tags: andfrom算法so数字weletx1
2条回答

range(a, b)包括a,不包括b。 因此这里的实际范围是:

{20, 25}
{30, 36}
{10, 39}
all_ranges = [range(20, 26), range(30, 37), range(10, 40)]

def get_combinations(ranges, k):
    if ranges.__len__() == 0:
        return int(k == 0)

    combinations = 0
    for i in ranges[0]:
#        if k - i < 0:
#            break
        combinations += get_combinations(ranges[1:], k - i)
    return combinations

print(get_combinations(all_ranges, 70))

我们将从k中减去数字,直到达到零,而不是将数字相加到k

if ranges.__len__() == 0:
    return int(k == 0)

这是终止递归的块。基本上,如果我们从k的范围中减去每个数字,那么结果必须是零

combinations = 0
for i in ranges[0]:
    combinations += get_combinations(ranges[1:], k - i)

请注意,注释的部分仅用于效率。 所以我们在这里选择一个数字,我们最初选择它为k。然后,我们循环第一个范围的所有值,并获得新范围k - i与新范围ranges[1:]的组合。你可以看到这些东西是如何结合在一起的

编辑并更正答案

对不起,我没注意到OP需要这些组合。尽管如此,我还是将上述代码留给了未来的访问者

使用与上面相同的逻辑,我们可以得到二维列表中的所有组合

from copy import deepcopy
all_ranges = [range(20, 26), range(30, 37), range(10, 40)]

def get_combinations(ranges, k, initial_combination=None):
    if not initial_combination:
        initial_combination = []
    combinations = []
    if ranges.__len__() == 1:
        for i in ranges[0]:
            if k - i < 0:
                return combinations
            elif k - i == 0:
                _ = deepcopy(initial_combination)
                _.append(i)
                combinations.append(_)
        return combinations

    for i in ranges[0]:
        _ = deepcopy(initial_combination)
        _.append(i)
        combinations += get_combinations(ranges[1:], k - i, _)
    return combinations

get_combinations(all_ranges, 70)

注:deepcopy functionality

计算效率黑客

from copy import deepcopy
all_ranges = [range(10, 40), range(20, 30), range(40, 50)]


def get_minimums():
    m = []
    for index, r in enumerate(all_ranges):
        m.append(sum([_.start for _ in all_ranges[index + 1:]]))

minimums = get_minimums() #[60, 40, 0]


def get_combinations(ranges, k, initial_combination=None):
    if not initial_combination:
        initial_combination = []
    combinations = []
    if ranges.__len__() == 1:
        for i in ranges[0]:
            if k - i < 0:
                break
            elif k - i == 0:
                _ = deepcopy(initial_combination)
                _.append(i)
                print(_)
                combinations.append(_)

        return combinations

    minimum = minimums[-ranges.__len__()]
    for i in range(ranges[0].start, ranges[0].stop):
        if k - minimum - i < 0:
            break

        _ = deepcopy(initial_combination)
        _.append(i)
        combinations += get_combinations(ranges[1:], k - i, _)
    return combinations

get_combinations(all_ranges, 90)

您可以使用itertools的乘积方法检查n个数组之间的所有组合

例如:

import itertools
a = [1,2]
b = ['a' , 'b']
c = list(itertools.product(a,b))
>> [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]

因此,如果您想知道构成给定数字的所有组合,只需在最终列表中迭代并检查所有结果

import itertools

x1 = range(25,35)
x2 = range(28,36)
x3 = range(15,20)

result = []
for item in list(itertools.product(x1,x2,x3)):
    if sum(item) == 75:
        result.append(item)

print(result)
>> [(25, 31, 19), (25, 32, 18), (25, 33, 17), (25, 34, 16), .....]

如果您以前不知道范围的数量,只需在itertools.product中使用*运算符,代码将是相同的

ranges = [range(1,5), range(5,29), range(3, 400), ...]

#STUFF

itertools.product(*ranges)

相关问题 更多 >