Java 如何将一组数字分成两组,使它们的和之差最小

Java 如何将一组数字分成两组,使它们的和之差最小,java,arrays,partition,Java,Arrays,Partition,如何编写一个Java程序,将一组数字分成两组,使它们各自数字之和的差值最小 例如,我有一个包含整数的数组-[5,4,8,2]。我可以把它分成两个数组-[8,2]和[5,4]。假设给定的一组数字,可以有一个唯一的解决方案,如上面的例子,如何编写一个Java程序来实现这个解决方案。即使我能找出可能的最小差异,也没关系。 假设我的方法接收一个数组作为参数。该方法必须首先将接收到的数组分成两个数组,然后将其中包含的整数相加。此后,它必须返回它们之间的差异,以使差异尽可能小 顺便说一下,我已经在这附近看过

如何编写一个Java程序,将一组数字分成两组,使它们各自数字之和的差值最小

例如,我有一个包含整数的数组-[5,4,8,2]。我可以把它分成两个数组-[8,2]和[5,4]。假设给定的一组数字,可以有一个唯一的解决方案,如上面的例子,如何编写一个Java程序来实现这个解决方案。即使我能找出可能的最小差异,也没关系。 假设我的方法接收一个数组作为参数。该方法必须首先将接收到的数组分成两个数组,然后将其中包含的整数相加。此后,它必须返回它们之间的差异,以使差异尽可能小

顺便说一下,我已经在这附近看过了,但是找不到任何具体的解决办法。这里似乎给出了最可能的解决方案-。但是我无法从这个线索中总结出如何编写Java程序来获得问题的明确解决方案

编辑:

在看了@Alexandru Severin的评论之后,我尝试了一个java程序。它适用于一组数字[1,3,5,9],但不适用于另一组数字[4,3,5,9,11]。下面是节目。请建议更改:-

 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;
    }
    }