一种从数字列表中找到所有不同总和的算法

时间:2019-04-09 02:14:36

标签: java algorithm data-structures combinations permutation

样本输入:

4 6 4 3 2 2 1 1

第一个数字=总数T(T <1000)

第二个数字=数字数S(S <= 12)

后面的S数字=数字的值(每个值<100)。 (可能会发生重复,输入的顺序是不递增的)

我的工作是使用列表中加起来为T的数字找到所有“不同的和”。

因此,该输入的示例输出为:

4
3+1
2+2
2+1+1

我的想法是逐一遍历列表,找到具有不同数字的所有数字组合,直到数字列表的大小-已评估的数字数量。您可以从每个组合中创建一个列表,然后将该列表添加到列表的HashSet中(HashSet可以防止重复)。

因此,您要检查所有1、2、3、4、5和6尺寸的组合,然后选择4种 然后将所有1、2、3、4、5个尺寸的组合与3搭配使用,而忽略4 然后将所有1、2、3、4大小的组合与2一起使用,而忽略4和3

  1. 我不确定该算法是否有效
  2. 在实现该算法方面,我都很难过。我无法围绕如何循环结构来获得所需的组合。

2 个答案:

答案 0 :(得分:1)

您应该尝试递归解决方案。通常,您只需要处理以下想法:对于每个数字,您都可以将其包括在总和中,也可以不包括。这意味着您正在构建数字的幂集,并且将得到O(2^N)解决方案。

简短地使用伪代码:

def get_all_sums(arr, target):

    result = []

    def helper(index, current_arr, current_sum):

        # once you've gone over the arr you can return. If all your numbers are positive
        # you can also return early if the current_sum > target
        if index == len(arr): return

        # solution found - add it to the result
        if current_sum == target: result.append(current_arr)

        # include the current index
        helper(index + 1, current_arr + [arr[index]], current_sum + arr[index])

        # don't include the current index
        helper(index + 1, current_arr, current_sum)

    helper(0, [], 0)

    # sort and hash to get rid of duplicates; return a set
    return {tuple(sorted(i) for i in result)}

答案 1 :(得分:0)

可以通过简单的递归找到答案,我将使用问题中的示例进行演示。

在递归的第一级,要解决的问题是

target=4 count=6 allowed={4,3,2,2,1,1} chosen={}

第一层在循环中选择每个唯一值,然后进行递归调用。因此,来自第一级的递归调用是

target=0 size=5 allowed={3,2,2,1,1} chosen={4}
target=1 size=4 allowed={2,2,1,1} chosen={3}
target=2 size=3 allowed={2,1,1} chosen={2}
target=3 size=1 allowed={1} chosen={1}

此处的关键是在每个递归级别上,允许值的数组会变小。只能使用跟随所选值的那些值。因此,例如,当第一级递归选择值3时,则仅允许小于3的值。如果是重复项,则选择第一个重复项,并将允许的值限制为其余重复项和任何较小的值。


参数处于第二级递归时

target=0 size=5 allowed={3,2,2,1,1} chosen={4}

这是成功的基本情况:target为0。在这种情况下,将{4}添加到输出列表,因为这是解决方案。


参数处于第二级递归时

target=1 size=4 allowed={2,2,1,1} chosen={3}

由于2大于目标,因此代码应跳过2。因此,唯一的递归调用是

target=0 size=1 allowed={1} chosen={3,1}

这也是基本情况,因此第三级递归会将<3,1}添加到输出中。


参数处于第二级递归时

target=2 size=3 allowed={2,1,1} chosen={2}

将有两个递归调用

target=0 size=2 allowed={1,1} chosen={2,2}
target=1 size=1 allowed={1} chosen={2,1}

第一个是基本情况,因此在输出中添加{2,2} 。另一个递归调用最终将将{2,1,1}添加到输出中


参数处于第二级递归时

target=3 size=1 allowed={1} chosen={1}

有一个递归调用

target=2 size=0 allowed={} chosen={1,1}

这是失败的基本情况:target不为零,size为0。


请注意,以这种方式解决问题后,仅生成唯一的解决方案,因此无需删除重复的解决方案。

还请注意,最大递归深度由S确定,因此将S限制在一个合理的较小数字(S <= 12则被视为合理的较小数字)非常重要。