如何找到一个数组的元素为特定值最接近的可能的总和?(How do I find the closes

2019-08-31 06:45发布

在Java中,我应该如何找到一个数组元素的最接近(或等于)可能和一个特定的值K?

例如,对于数组{19,23,41,5,40,36}和K = 44,最接近的可能之和为23 + 19 = 42。 我一直挣扎在这几个小时; 我几乎一无所知动态规划。 顺便说一句,该数组只包含正数。

Answer 1:

您通常会使用动态编程这样的问题。 然而,这基本上归结为保持一组可能的和的和将输入值一个接一个,如在下面的代码,并且具有相同的渐近运行时间: O(n K)其中n是您输入的大小阵列和K是目标值。

下面的版本的常量可能是更大的,但是,但是我觉得代码更容易跟踪,比动态规划版本会。

public class Test {
    public static void main(String[] args) {
        int K = 44;
        List<Integer> inputs = Arrays.asList(19,23,41,5,40,36);

        int opt = 0;                // optimal solution so far          

        Set<Integer> sums = new HashSet<>();
        sums.add(opt);

        // loop over all input values
        for (Integer input : inputs) {
            Set<Integer> newSums = new HashSet<>();

            // loop over all sums so far                        
            for (Integer sum : sums) {
                int newSum = sum + input;

                // ignore too big sums
                if (newSum <= K) {
                    newSums.add(newSum);

                    // update optimum                       
                    if (newSum > opt) {
                        opt = newSum;
                    }
                }
            }

            sums.addAll(newSums);
        }

        System.out.println(opt);
    }
}

编辑

因为我只是声称对运行时间的简短的笔记可能是有用的, O(n K)没有正当理由。

显然,初始化和打印结果只是需要一定的时间,所以我们应该分析双回路。

外环运行在所有输入,所以它的主体中执行n倍。

内环上的所有款项,运行至今,这可能是在理论上一个指数。 但是 ,我们使用的上限的K ,所以在所有的值sums的范围是[0, K] 因为sums是一组,它含有至多K+1的元件。

内环内所有的计算采取恒定时间,所以总循环花费O(K) 该组newSums还含有至多K+1的元件,由于相同的原因,所以addAll到底需要O(K)为好。

结束语:外循环执行n次。 循环体花费O(K) 因此,该算法在运行O(n K)

编辑2

在关于如何还发现,导致最佳的总和要素的要求:

子列表的总和 - - 而不是保持一个整数的轨道,你也应该跟踪的子表本身。 如果你创建一个新的类型(没有getter / setter方法保持示例简洁)这是一个相对简单:

public class SubList {
    public int size;
    public List<Integer> subList;

    public SubList() {
        this(0, new ArrayList<>());
    }

    public SubList(int size, List<Integer> subList) {
        this.size = size;
        this.subList = subList;
    }
}

初始化现在变成:

SubList opt = new SubList();

Set<SubList> sums = new HashSet<>();
sums.add(opt);  

在内环sums需要一些小的调整,以及:

for (Integer input : inputs) {
    Set<SubList> newSums = new HashSet<>();

    // loop over all sums so far                        
    for (SubList sum : sums) {
        List<Integer> newSubList = new ArrayList<>(sum.subList);
        newSubList.add(input);
        SubList newSum = new SubList(sum.size + input, newSubList);         

        // ignore too big sums
        if (newSum.size <= K) {
            newSums.add(newSum);

            // update optimum                       
            if (newSum.size > opt) {
                opt = newSum;
            }
        }
    }

    sums.addAll(newSums);
}


Answer 2:

你可以把它看成是n-choose-k问题的所有可能k所以复杂性是指数 。

  1. 找到了一组数字,金额最多可达K 。 该组应该包括i数字, i=1; i<=N; i++ i=1; i<=N; i++ i=1; i<=N; i++ 。 为了实现这一点,每个i只是把所有的n-choose-i 的组合阵列中的数字。
  2. 保持finalResult与数字的迄今为止发现的最好的一套和它们的和可变的。
  3. 比较步骤1与每个子结果finalResult并在必要时进行更新。

这让我想起了的背包问题 ,所以你可能想看看它。



Answer 3:

我想说的第一个数组排序。 然后,你的例子是:ARR = {5,19,23,36,40,41}。 然后:1)取的常用3 [0]和常用3 [I],其中i = arr.Size。 概括并记录之和K之间的差,如果该总和大于K. 2)如果总和>该k低,执行步骤1,但不是ARR [I]中,使用ARR [I-1],因为我们要降低我们的总和。 如果总和<K,执行步骤1,但不是ARR [0],使用ARR [1],因为我们要提高我们的总和。 不断重复步骤2,通过增加或减少的索引,直到两个元件的索引相等。 然后,我们知道对元素导致的总和和K之间的最小差异

----------------在溶液中为编辑单元的任意数量----------------

我相信你可能需要一棵树。 下面是我在想什么:

1)选择一个号码作为顶级节点。

2)对于该集合中的每个数字,创建一个子节点,而对于所创建的每个分支,计算该分支的总和。

3)如果总和小于K,我们再次分支,在集合的所有元素创建子节点。 如果总和大于K,我们停止,保持总和与K(如果总和<K)之间的差异。 如果我们找到一个更好的和一个分支,那么我们保持这一分支。 重复这个过程,直到所有分支进行分支。

执行步骤1-3不同topnodes。



文章来源: How do I find the closest possible sum of an Array's elements to a particular value?