将数组分割成差值最小的子集

本文使用掩码实现一个功能 ==》将数组分割成差值最小的子集


JAVA代码如下:

import java.util.Arrays;  
  
public class MinimalDifference {  
  
    /** 
     * 将数组分割成差值最小的子集 
     */  
    public void printTwoMinDiffGroups(int[] values) {  
  
        int length = values.length;  
        // 长度为length的二进制表示个数有1<<length个  
        int allMasks = 1 << length;  
        int min = Integer.MAX_VALUE;  
        int value = 0;  
        for (int i = allMasks - 1; i >= 0; i--) {  
            int diff = 0;  
            for (int j = 0; j < length; j++) {  
                diff += (i & (1 << j)) == 0 ? values[j] : -values[j];  
  
            }  
            if (Math.abs(diff) < min) {  
                min = Math.abs(diff);  
                value = i;  
            }  
        }  
  
        /* 
         * 将上述计算得到的value值,与二进制表示相比较 
         *  
         * 1. value & (1 << j)) == 0 2. ((value & (1 << j)) == (1 << j)) 
         */  
  
        System.out.printf("原数组  %s 分割成两个和最接近的数组如下:\n", Arrays.toString(values));  
        System.out.print("数组一的内容: ");  
        for (int j = 0; j < length; j++) {  
            System.out.print(((value & (1 << j)) == 0) ? values[j] + " " : "");  
        }  
  
        System.out.print("\n数组二的内容: ");  
        for (int j = 0; j < length; j++) {  
            System.out.print(((value & (1 << j)) == (1 << j)) ? values[j] + " "  
                    : "");  
        }  
  
    }  
  
}  

 

一个测试例子, 分割数组[1, 2, 3, 6, 4, 7, 9]。

public class Test {  
  
    public static void main(String[] args) {  
            new MinimalDifference().printTwoMinDiffGroups(new int[] { 1, 2, 3, 6,  
                    4, 7, 9 });  
    }  
}  

 运行结果:

原数组  [1, 2, 3, 6, 4, 7, 9] 分割成两个和最接近的数组如下:
数组一的内容: 1 2 3 6 4
数组二的内容: 7 9

 

二、将一个数组分成2个数组,使得2个数组的差值最小

  /**
     * 用java写个程序,将一个数组分成2个数组,使得2个数组的差值最小
     * 思路是:
     1).先求出数组的总和sum, sum/2=mid
     2).然后将数组的元素跟mid比较,取出跟mid最接近的元素,放在第一个小数组里,然后在原来数组删除刚刚被取出的元素,更新原来数组
     3).接着再取出离mid最近的元素,放在第二个小数组,在原数组中删除刚刚被取出的元素,更新原来数组
     4).遍历原来数组,重复2和3,往后的元素放在第一个小数组或者第二个小数组,取决于两个小数组的所有元素的总和,哪个总和小就放在哪个小数组
     */
    public static int[][]  binaryMiun(int[] Arrint){
       //遍历数组求元素的总和sum
        int sum = sumArr(Arrint);
        //mid 为元素总和的一半
        int mid = sum/2;
        int suml = 0;//第一个小数组元素总和
        int sumr = 0;//第二个小数组元素的总和
        int[] l = new int[Arrint.length] ;//第一个小数组
        int[] r =  new int[Arrint.length] ;//第二个小数组
 
        int lcount = 0;
        int rcount = 0;
        int n = Arrint.length;
        for(int h= 0; h < n;) {
            int min = mid - Arrint[0];
            int j = 0;
            //找出离mid最近的元素
            for(int i=0;i<n;i++){
                int temp = mid - Arrint[i];
                if(temp<=mid){
                    min = temp;
                    //距离mid最近的元素的下标
                    j = i;
                }
            }
            //将取出的元素放在元素总和较小的数组
            if(suml <= sumr){
                l[lcount++]  = Arrint[j];
                suml += Arrint[j];
            }else{
                r[rcount++]  = Arrint[j];
                sumr += Arrint[j];
            }
            //将刚刚在原数组取出的元素删除,更新原数组
           /* for(int k= j ;k<n;k++){
             Arrint[k] = Arrint[k+1];
            }*/
            Arrint = delAnyPosition(Arrint,j);
            n--;
        }
        int[][] lr = {Arrays.copyOf(l,lcount),Arrays.copyOf(r,rcount)};
        return lr;
    }
  /**
     * 数组求和
     * @param arr
     * @return
     */
    public static int sumArr(int[] arr){
        int sum = 0;
        for(int i=0;i<arr.length;i++){
            sum += arr[i];
        }
        return sum;
    }

 

posted @ 2022-04-24 12:12  古语云  阅读(303)  评论(0编辑  收藏  举报