将数组分割成差值最小的子集
本文使用位掩码实现一个功能 ==》将数组分割成差值最小的子集
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; }