Java 如何将一组数字分成两组,使它们的和之差最小
如何编写一个Java程序,将一组数字分成两组,使它们各自数字之和的差值最小 例如,我有一个包含整数的数组-[5,4,8,2]。我可以把它分成两个数组-[8,2]和[5,4]。假设给定的一组数字,可以有一个唯一的解决方案,如上面的例子,如何编写一个Java程序来实现这个解决方案。即使我能找出可能的最小差异,也没关系。 假设我的方法接收一个数组作为参数。该方法必须首先将接收到的数组分成两个数组,然后将其中包含的整数相加。此后,它必须返回它们之间的差异,以使差异尽可能小 顺便说一下,我已经在这附近看过了,但是找不到任何具体的解决办法。这里似乎给出了最可能的解决方案-。但是我无法从这个线索中总结出如何编写Java程序来获得问题的明确解决方案 编辑: 在看了@Alexandru Severin的评论之后,我尝试了一个java程序。它适用于一组数字[1,3,5,9],但不适用于另一组数字[4,3,5,9,11]。下面是节目。请建议更改:-Java 如何将一组数字分成两组,使它们的和之差最小,java,arrays,partition,Java,Arrays,Partition,如何编写一个Java程序,将一组数字分成两组,使它们各自数字之和的差值最小 例如,我有一个包含整数的数组-[5,4,8,2]。我可以把它分成两个数组-[8,2]和[5,4]。假设给定的一组数字,可以有一个唯一的解决方案,如上面的例子,如何编写一个Java程序来实现这个解决方案。即使我能找出可能的最小差异,也没关系。 假设我的方法接收一个数组作为参数。该方法必须首先将接收到的数组分成两个数组,然后将其中包含的整数相加。此后,它必须返回它们之间的差异,以使差异尽可能小 顺便说一下,我已经在这附近看过
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FindMinimumDifference {
public static void main(String[] args) {
int[] arr= new int[]{4,3,5,9, 11};
FindMinimumDifference obj= new FindMinimumDifference();
obj.returnMinDiff(arr);
}
private int returnMinDiff(int[] array){
int diff=-1;
Arrays.sort(array);
List<Integer> list1= new ArrayList<>();
List<Integer> list2= new ArrayList<>();
int sumOfList1=0;
int sumOfList2=0;
for(int a:array){
for(Integer i:list1){
sumOfList1+=i;
}
for(Integer i:list2){
sumOfList2+=i;
}
if(sumOfList1<=sumOfList2){
list1.add(a);
}else{
list2.add(a);
}
}
List<Integer> list3=new ArrayList<>(list1);
List<Integer> list4= new ArrayList<>(list2);
Map<Integer, List<Integer>> mapOfProbables= new HashMap<Integer, List<Integer>>();
int probableValueCount=0;
for(int i=0; i<list1.size();i++){
for(int j=0; j<list2.size();j++){
if(abs(list1.get(i)-list2.get(j))<
abs(getSumOfEntries(list1)-getSumOfEntries(list2))){
List<Integer> list= new ArrayList<>();
list.add(list1.get(i));
list.add(list2.get(j));
mapOfProbables.put(probableValueCount++, list);
}
}
}
int minimumDiff=abs(getSumOfEntries(list1)-getSumOfEntries(list2));
List resultList= new ArrayList<>();
for(List probableList:mapOfProbables.values()){
list3.remove(probableList.get(0));
list4.remove(probableList.get(1));
list3.add((Integer)probableList.get(1));
list4.add((Integer)probableList.get(0));
if(minimumDiff>abs(getSumOfEntries(list3)-getSumOfEntries(list4))){
// valid exchange
minimumDiff=abs(getSumOfEntries(list3)-getSumOfEntries(list4));
resultList=probableList;
}
}
System.out.println(minimumDiff);
if(resultList.size()>0){
list1.remove(resultList.get(0));
list2.remove(resultList.get(1));
list1.add((Integer)resultList.get(1));
list2.add((Integer)resultList.get(0));
}
System.out.println(list1+""+list2); // the two resulting set of
// numbers with modified data giving expected result
return minimumDiff;
}
private static int getSumOfEntries(List<Integer> list){
int sum=0;
for(Integer i:list){
sum+=i;
}
return sum;
}
private static int abs(int i){
if(i<=0)
i=-i;
return i;
}
}
import java.util.ArrayList;
导入java.util.array;
导入java.util.HashMap;
导入java.util.List;
导入java.util.Map;
公共类FindMinimumDifference{
公共静态void main(字符串[]args){
int[]arr=新的int[]{4,3,5,9,11};
FindMinimumDifference obj=新的FindMinimumDifference();
目标:返回警犬(arr);
}
私有int returnMinDiff(int[]数组){
int-diff=-1;
数组。排序(数组);
List list1=新的ArrayList();
List list2=新的ArrayList();
int sumOfList1=0;
int sumOfList2=0;
for(int a:array){
for(整数i:list1){
sumOfList1+=i;
}
for(整数i:list2){
sumOfList2+=i;
}
如果(sumOfList1这是分区问题的一个变体
如果你想要最佳的解决方案,你必须测试输出集的每一个可能的组合。这可能对小的集合是可行的,但对大的输入是不可行的
一个很好的近似是我下面介绍的贪婪算法
当集合中的数字为
与基数大小相同或更小,但不是
保证产生最好的分区
首先,您需要将输入放入可排序的集合(如列表)中
1) 对输入集合进行排序
2) 创建2个结果集
3) 迭代排序后的输入。如果索引为偶数,则将该项放入结果1,否则将该项放入结果2
List<Integer> input = new ArrayList<Integer>();
Collections.sort(input);
Set<Integer> result1 = new HashSet<Integer>();
Set<Integer> result2 = new HashSet<Integer>();
for (int i = 0; i < input.size(); i++) {
if (i % 2 == 0) {// if i is even
result1.add(input.get(i));
} else {
result2.add(input.get(i));
}
}
List input=new ArrayList();
集合。排序(输入);
Set result1=新的HashSet();
Set result2=新的HashSet();
对于(int i=0;i
似乎您对算法比对代码更感兴趣。因此,以下是我的psuedocode:-
int A[];//This contains your elements in sorted (descending) order
int a1[],a2[];//The two sub-arrays
int sum1=0,sum2=0;//These store the sum of the elements of the 2 subarrays respectively
for(i=0;i<A.length;i++)
{
//Calculate the absolute difference of the sums for each element and then add accordingly and thereafter update the sum
if(abs(sum1+A[i]-sum2)<=abs(sum2+A[i]-sum1))
{a1.add(A[i]);
sum1+=A[i];}
else
{a2.add(A[i]);
sum2+=A[i];}
}
int A[];//这包含按排序(降序)顺序排列的元素
int a1[],a2[];//两个子数组
int sum1=0,sum2=0;//它们分别存储2个子数组的元素之和
对于(i=0;i首先,排序数组,然后将第一个成员放入组中,将第二个成员放入另一个伤口中,这是不可行的,原因如下:
给定输入[1,2,3100]
。
结果将是:[1,3]
和[2100]
,显然是错误的。
正确答案应该是:[1,2,3]
和[100]
你可以在谷歌上找到许多针对这个问题的优化算法,但既然我假设你是初学者,我将尝试给你一个简单的算法,你可以实现:
对数组进行排序
从最高值迭代到最低值
对于每个迭代,计算每个组的总和,然后将元素添加到具有最小总和的组中
在循环结束时,您应该有两个相当平衡的数组。例如:
Array: [1,5,5,6,7,10,20]
i1: `[20] []`
i2: `[20] [10]`
i3: `[20] [10,7]`
i4: `[20] [20,7,6]`
i5: `[20,5] [10,7,6]`
i6: `[20,5] [10,7,6,5]`
i7: `[20,5,1] [10,7,6,5]`
其中,和是26
和28
。正如您所见,我们可以进一步优化解决方案,如果我们交换5
和6
,得到[20,6,1]
和[20,7,5,5]
,那么和是相等的
对于此步骤,您可以:
查找所有元素组(x,y)
,其中x
在组1中,y
在组2中,以及|x-y |<| sum(组1)-sum(组2)|
循环所有组并尝试用y
交换x
,直到得到最小的差异
每次交换后,检查具有最高总和的组中的最小值是否高于组之间的差值,如果是,则将其转移到另一组
此算法始终会返回最佳解,比贪婪方法要好得多。但是,就复杂性、速度和内存而言,它不是最优的。如果需要非常大的阵列并且资源有限,则最佳算法可能会因速度/内存比率和可接受的错误百分比a而有所不同ge.对于这个问题,假设我们可以将数组分成两个子数组,使它们的和相等。(即使它们不相等,也可以工作)
因此,如果数组中的元素之和是S,那么您的目标是找到一个和为S/2的子集。您可以为此编写一个递归函数
int difference = Integer.MAX_VALUE;
public void recursiveSum(int[] array, int presentSum, int index,Set<Integer> presentSet){
if(index == array.length){
if(Math.abs(presentSum - (S/2)) < difference)){
difference = Math.abs(presentSum - (S/2);
// presentSet is your answer
return;
}
}
recursiveSum(array,presentSum,index+1,presentSet); // don't consider the present element in the final solution
presentSet.add(array[index]);
recursiveSum(array,presentSum + array[index],index+1,presentSet); //consider the present element in the final solution
}
int差=Integer.MAX\u值;
public void recursiveSum(int[]数组、int presentSum、int索引、Set presentSet){
if(index==array.length){
if(算术绝对值(当前总和-(S/2))<差值)){
差值=数学绝对值(当前总和-(S/2);
//现在就是你的答案
返回;
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FindMinimumDifference {
static List<Integer> list1= new ArrayList<>();
static List<Integer> list2= new ArrayList<>();
public static void main(String[] args) {
int[] arr= new int[]{3,-2,9,7};
// tested for these sample data:- [1,5,9,3] ; [4,3,5,9,11] ;
//[7,5,11,2,13,15,14] ; [3,2,1,7,9,11,13] ;
//[3,1,0,5,6,9] ; [6,8,10,2,4,0] ; [3,1,5,7,0] ; [4,-1,5,-3,7] ; [3,-2,9,7]
System.out.println("the minimum possible difference is: "+returnMinDiff(arr));
System.out.println("the two resulting set of nos. are: "+list1+" and "+list2);
}
private static int returnMinDiff(int[] array){
int diff=-1;
Arrays.sort(array);
for(int a:array){
int sumOfList1=0;
int sumOfList2=0;
for(Integer i:list1){
sumOfList1+=i;
}
for(Integer i:list2){
sumOfList2+=i;
}
if(sumOfList1<=sumOfList2){
list1.add(a);
}else{
list2.add(a);
}
}
List<Integer> list3=new ArrayList<>(list1);
List<Integer> list4= new ArrayList<>(list2);
if(list3.size()!=list4.size()){ // both list should contain equal no. of entries.
//If not, add 0 to the list having lesser no. of entries
if(list3.size()<list4.size()){
list3.add(0);
}else{
list4.add(0);
}
}
Map<Integer, List<Integer>> mapOfProbables= new HashMap<Integer, List<Integer>>();
int probableValueCount=0;
for(int i=0; i<list3.size();i++){
for(int j=0; j<list4.size();j++){
if(abs(list3.get(i)-list4.get(j))
<abs(getSumOfEntries(list3)-getSumOfEntries(list4))){
List<Integer> list= new ArrayList<>();
list.add(list3.get(i));
list.add(list4.get(j));
mapOfProbables.put(probableValueCount++, list);
}
}
}
int minimumDiff=abs(getSumOfEntries(list1)-getSumOfEntries(list2));
List resultList= new ArrayList<>();
for(List probableList:mapOfProbables.values()){
list3=new ArrayList<>(list1);
list4= new ArrayList<>(list2);
list3.remove(probableList.get(0));
list4.remove(probableList.get(1));
list3.add((Integer)probableList.get(1));
list4.add((Integer)probableList.get(0));
if(minimumDiff>abs(getSumOfEntries(list3)-getSumOfEntries(list4))){ // valid exchange
minimumDiff=abs(getSumOfEntries(list3)-getSumOfEntries(list4));
resultList=probableList;
}
}
if(resultList.size()>0){ // forming the two set of nos. whose difference of sum comes out to be minimum
list1.remove(resultList.get(0));
list2.remove(resultList.get(1));
if(!resultList.get(1).equals(0) ) // (resultList.get(1).equals(0) && !list1.contains(0))
list1.add((Integer)resultList.get(1));
if(!resultList.get(0).equals(0) || (resultList.get(0).equals(0) && list2.contains(0)))
list2.add((Integer)resultList.get(0));
}
return minimumDiff; // returning the minimum possible difference
}
private static int getSumOfEntries(List<Integer> list){
int sum=0;
for(Integer i:list){
sum+=i;
}
return sum;
}
private static int abs(int i){
if(i<=0)
i=-i;
return i;
}
}