输入为[4,13,14,15,16]
。输出应为[16,15]
和[14,13,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);
}
}
}
}
输出
[16,13,4]
。[15,14]
。看起来我的算法需要进一步改进。对我而言,这似乎是一个NP问题。但我无法想到这里给出输出的算法
[16,15]
和[14,13,4]
。
答案 0 :(得分:6)
这是knapsack problem。在一般情况下它是NP完全的,但对于小整数,它可以有效地解决。
我们来看一下[4,13,14,15,16]
的示例数组。总数是62.我们将其改为背包问题,我们有这套项目,但背包容量是62÷2 = 31.如果我们选择总数不超过31的项目,那么这解决了你的问题最小化两个分开列表之间差异的问题。
有一个解决背包问题的标准算法,我在这里不再解释。
答案 1 :(得分:1)
我理解你的问题:你想要将数组分成两个数组,每个数组的总和最小。
您应该在添加list1Sum
后对list2Sum
和i
进行比较,以便:
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);
}
}
}