将数组划分为两个子数组,以便数组总和之间的差异最小?

时间:2016-07-30 15:52:09

标签: java arrays algorithm

输入为[4,13,14,15,16]。输出应为[16,15][14,13,4]

我可以想到以下算法

  1. 我按降序排列数组
  2. 取两个列表中的前两个元素
  3. 现在在列表中添加sum为最小的元素
  4. public class TestMinDiff {
    
        public static void main(String[] args) {
            Integer[] array = {4,13,14,15,16};
    
            Arrays.sort(array, Collections.reverseOrder());
    
            List<Integer> list1 = new ArrayList<Integer>();
            List<Integer> list2 = new ArrayList<Integer>();
    
            int list1Sum = 0;
            int list2Sum = 0;
    
            for(int i: array) {
                if(list1Sum<=list2Sum) {
                    list1Sum = list1Sum + i;
                    list1.add(i);
                } else {
                    list2Sum = list2Sum + i;
                    list2.add(i);
                }
            }
        }
    }
    

    输出

    1. 列表1是[16,13,4]
    2. 列表2是[15,14]
    3. 看起来我的算法需要进一步改进。对我而言,这似乎是一个NP问题。但我无法想到这里给出输出的算法 [16,15][14,13,4]

3 个答案:

答案 0 :(得分:6)

这是knapsack problem。在一般情况下它是NP完全的,但对于小整数,它可以有效地解决。

我们来看一下[4,13,14,15,16]的示例数组。总数是62.我们将其改为背包问题,我们有这套项目,但背包容量是62÷2 = 31.如果我们选择总数不超过31的项目,那么这解决了你的问题最小化两个分开列表之间差异的问题。

有一个解决背包问题的标准算法,我在这里不再解释。

答案 1 :(得分:1)

我理解你的问题:你想要将数组分成两个数组,每个数组的总和最小。 您应该在添加list1Sum后对list2Sumi进行比较,以便:

if(list1Sum + i <= list2Sum){
            list1Sum= list1Sum +i;
            list1.add(i);
        }else{
            list2Sum= list2Sum +i;
            list2.add(i);
        }

答案 2 :(得分:0)

我同意Nayuki算法。它的背包问题有一个维度,你可以考虑所有输入的值与输入(或权重)相同。

现在找到两个子数组,其总和小于等于31

import java.util.ArrayList;
import java.util.List;
public class Knapsack {

    public static void main(String[] args) {

        int[] weight = {4,13,14,15};
        int[] value = {4,13,14,15};
        int targetSum = 31;

        knapsack(weight, value, targetSum);

    }

    public static void knapsack(int[] weight, int[] value, int targetSum) {

        int[][] weightValMatrix = new int[weight.length + 1][targetSum + 1];

        for (int i = 0; i < weight.length; i++) {
            for (int k = 0; k < targetSum + 1; k++) {
                weightValMatrix[i][k] = 0;
            }

        }

        for (int i = 1; i < weight.length + 1; i++) {
            for (int k = 1; k < targetSum + 1; k++) {
                if (k < weight[i - 1]) {
                    weightValMatrix[i][k] = weightValMatrix[i - 1][k];
                } else {
                    int valueInclusiveCurrentWeight = value[i - 1];
                    if ((k - weight[i - 1]) > 0) {
                        valueInclusiveCurrentWeight = valueInclusiveCurrentWeight
                                + weightValMatrix[i - 1][k - weight[i - 1]];
                    }

                    int valueExcludingCurrentWeight = weightValMatrix[i - 1][k];
                    weightValMatrix[i][k] = valueInclusiveCurrentWeight >= valueExcludingCurrentWeight ? valueInclusiveCurrentWeight
                            : valueExcludingCurrentWeight;

                }

            }



        }



        for (int i = 1; i < weight.length + 1; i++) {

            for (int k = 1; k < targetSum + 1; k++) {

                System.out.print(weightValMatrix[i][k]);

                if(k == targetSum){
                    System.out.println("");
                }
            }
        }


        System.out.println("final value is " + weightValMatrix[weight.length][targetSum]);

        List<Integer> finallySelectedWeightIndex = new ArrayList<Integer>();

        findActualWeightIndex(weightValMatrix, weight.length, targetSum, finallySelectedWeightIndex, weight);

        for(int index:finallySelectedWeightIndex){
            System.out.println("weight is " + weight[index-1] + " value is "+ value[index-1]);
        }


    }


    public static void findActualWeightIndex(int[][] weightValMatrix, int row, int column, 
            List<Integer> finallySelectedWeightIndex, int[] weight) {

        if(row==0 || column==0){
            return;
        }

        if(weightValMatrix[row][column]==weightValMatrix[row-1][column]){
            findActualWeightIndex(weightValMatrix, row-1, column, finallySelectedWeightIndex, weight);
        }else{
            finallySelectedWeightIndex.add(row);
            findActualWeightIndex(weightValMatrix, row-1, column - weight[row-1] , finallySelectedWeightIndex, weight);
        }
    }

}