如何生成等于给定输入的两个数字的组合

时间:2018-09-18 17:53:03

标签: python combinations

我正在尝试仅使用5和7生成两个数字的组合,这将等于任何给定输入的总和。输入范围是24:1000。到目前为止,我所做的是确定输入是否可以被5或7整除,然后生成一个总和等于输入的列表。
这是我的工作示例:

def change(amount):
    if amount not in range(24,1001):
       print("The number is outside the range.")
    else:
       remainder=amount%5
    if remainder==0:
       n = int(amount/5)
       array=[0 for i in range(n)]
       for i in range(n):
       array[i]=5
       return array, sum(array)
    else:
       remainder=amount%7
    if remainder==0:
       n = int(amount/7)
       array=[0 for i in range(n)]
       for i in range(n):
       array[i]=7
       return array, sum(array)
    else: 
     # here is where am stuck       
print(change(28))

输出必须为数组形式。例如:对于change(24),数组应为[5,5,7,7]。

4 个答案:

答案 0 :(得分:2)

我能想到的最简单的方法

def change(target):
    if target not in range(24,1001):
           raise ValueError("The number is outside the range.")
    res = []
    while target % 5 != 0:
        res.append(7)
        target -= 7

    while target != 0:
        res.append(5)
        target -= 5

    return res


change(28)
>>> [7, 7, 7, 7]

答案 1 :(得分:1)

您不需要循环,只需要一点代数。有关详细信息,请参见评论。

def change(amount):
    if not 24 <= amount <= 1000:
       print("The number is outside the range.")
       return None

    # 5*3 - 7*2 = 1, so 5*(3*n) + 7*(-2*n) = n, and therefore
    # 5*(3*n - 7*k) + 7*(5*k - 2*n) = n for all k
    # We want to find a small k so that the terms in each bracket are positive
    k = 3 * amount // 7
    x = 3 * amount - 7 * k
    y = 5 * k - 2 * amount
    return x, y, [5] * x + [7] * y

# Print the sequences for some small amounts
for i in range(24, 70):
    x, y, seq = change(i)
    print(i, x, y, sum(seq) == i)

# Check all values in the range
for i in range(24, 1001):
    x, y, seq = change(i)
    assert sum(seq) == i
print('ok')

输出

24 2 2 True
25 5 0 True
26 1 3 True
27 4 1 True
28 0 4 True
29 3 2 True
30 6 0 True
31 2 3 True
32 5 1 True
33 1 4 True
34 4 2 True
35 0 5 True
36 3 3 True
37 6 1 True
38 2 4 True
39 5 2 True
40 1 5 True
41 4 3 True
42 0 6 True
43 3 4 True
44 6 2 True
45 2 5 True
46 5 3 True
47 1 6 True
48 4 4 True
49 0 7 True
50 3 5 True
51 6 3 True
52 2 6 True
53 5 4 True
54 1 7 True
55 4 5 True
56 0 8 True
57 3 6 True
58 6 4 True
59 2 7 True
60 5 5 True
61 1 8 True
62 4 6 True
63 0 9 True
64 3 7 True
65 6 5 True
66 2 8 True
67 5 6 True
68 1 9 True
69 4 7 True
ok

这不一定会为每个数量提供最短的序列,但是通常接近最佳值,并且修改此代码以获取最佳值并不是很困难。但这将留给读者练习。 ;)

要了解有关此技术的更多信息,请参阅有关线性Diophantine equations的Wikipedia文章。

答案 2 :(得分:0)

这是我能想到的最快的方法,因为它只使用一个while周期。

def change(amount):
    if not 24 <= amount <= 1001:
        print('{} is outside range'.format(amount))
        return
    sevens = []
    fives, remainder = divmod(amount, 5)
    while remainder:
        amount -= 7
        sevens.append(7)
        fives, remainder = divmod(amount, 5)
    return [5] * fives + sevens

PS:请不要混合列表大小:-)

答案 3 :(得分:0)

对于所有组合,这里都是一个主意。循环可以进一步优化

    #titlebar a{
        display: inline-block;
    }

还有一点优化。收集可能范围内的所有组合,并用sum == target过滤掉组合。

import itertools


def change(target):
    nums = [5, 7]
    min_len = int(target / 7)
    max_len = int(target / 5) + 1

    res = []
    for len_ in range(min_len, max_len):
        r = itertools.combinations_with_replacement(nums, len_)
        for item in r:
            if sum(item) == target:
                res.append(item)

    return res

包含目标= 70的所有可能组合的输出

import itertools


def change(target):
    nums = [5, 7]
    min_len = int(target / 7)
    max_len = int(target / 5) + 1

    res = []
    for len_ in range(min_len, max_len):
        res += (list(itertools.combinations_with_replacement(nums, len_)))

    return list(filter(lambda x: sum(x) == target, res))

FP样式中没有任何循环。将所有可能的组合简化为一个列表,然后过滤此列表的正确元素。

[(7, 7, 7, 7, 7, 7, 7, 7, 7, 7), (5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7), (5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5)]