package algorithm; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.TreeMap; /** * * @Description: n个数按顺序分成m组,每组和尽量相近 * 思路:先递归求出所有切分点的组合方式,然后分别计算每组中的和,对每组和两两差值的绝对值累加,最小的为最优切分点。 * 如:{1,2,3,4}分2组 可以{1}和{2,3,4} {1,2}和{3,4} {1,2,3}和{4} 不能为{1,3}{2,4} * 缺点:当list很大,分的组很多的时候,效率很低,几十分钟才能算出来。 * @author thrillerzw * @version 1.0 * @create time 2014-4-28 下午6:47:19 */ public class TestCombination { public static void main(String[] args) { List<Integer> lengthList = new ArrayList<Integer>(); for(int i=0;i<6;i++){ lengthList.add(new Random().nextInt(100)); } long startTime=System.currentTimeMillis(); int m = 3; List<List<Integer>> resultList = new ArrayList<List<Integer>>(); if (lengthList.size() < m) { buildResultList(resultList, lengthList); } else { int endIndex = lengthList.size() - (m - 2); int[] tempArr = new int[m - 1]; List<int[]> combList = new ArrayList<int[]>(); int num = -1; //所有切分点的组合存入combList Combine(lengthList, m - 1, tempArr, 0, 0, combList); int[] resultArr = null; for (int[] combArr : combList) { for (int i = 0; i < combArr.length; i++) { System.out.print(combArr[i] + " "); } System.out.println(); int[] sumArr = getSum(combArr, lengthList); int diffSum = computeDifferent(sumArr); if (diffSum < num || num == -1) { num = diffSum; System.out.println("num=" + num); resultArr = combArr; } } if (resultArr != null) { for (int result : resultArr) { System.out.print(result + " "); } } buildResultList(resultList, lengthList, resultArr); } long endTime=System.currentTimeMillis(); long useTime=endTime-startTime; System.out.print(lengthList.size()+"个数分为"+m+"组使用毫秒时间"+useTime+" resultList=" + resultList); } //如果分组数m大于等于集合的长度。 static void buildResultList(List<List<Integer>> resultList, List<Integer> dataList) { for (int i = 0; i < dataList.size(); i++) { List<Integer> list = new ArrayList<Integer>(); list.add(dataList.get(i)); resultList.add(list); } } // 根据最优切分点构建结果集 static void buildResultList(List<List<Integer>> resultList, List<Integer> dataList, int[] resultArr) { if (resultList == null || dataList == null || resultArr == null) { return; } int j = 0; int maxJ = 0; for (int i = 0; i <= resultArr.length; i++) { if (i == resultArr.length) { maxJ = dataList.size(); } else { maxJ = resultArr[i]; } List<Integer> list = new ArrayList<Integer>(); for (; j < maxJ; j++) { list.add(dataList.get(j)); } resultList.add(list); } } //每种组合不同段的和。比如0--2 2--5 5--list的结尾 static int[] getSum(int[] combArr, List<Integer> dataList) { if (combArr == null || dataList == null) { return null; } int[] sumArr = new int[combArr.length + 1]; int j = 0; int sum = 0; int maxJ = 0; for (int i = 0; i <= combArr.length; i++) { if (i == combArr.length) { maxJ = dataList.size(); } else { maxJ = combArr[i]; } for (; j < maxJ; j++) { sum += dataList.get(j); } sumArr[i] = sum; System.out.println("sum=" + sum); sum = 0; } return sumArr; } // 数组中值两两比较,差的绝对值的和累加 static int computeDifferent(int[] sumArr) { int diffSum = 0; for (int i = 0; i < sumArr.length; i++) { for (int j = i + 1; j < sumArr.length; j++) { diffSum += Math.abs(sumArr[i] - sumArr[j]); } } System.out.println("diffSum=" + diffSum); return diffSum; } // 所有切分点组合 private static void Combine(List<Integer> lengthList, int num, int[] tempArr, int tempArrIndex, int low, List<int[]> combList) { if (lengthList == null || lengthList.size() < num) { return; } if (num == 0) { if (tempArr[tempArr.length - 1] != lengthList.size()) { combList.add(tempArr); } } else { for (int i = low; i < lengthList.size(); i++) { tempArr[tempArrIndex] = i + 1; Combine(lengthList, num - 1, tempArr, ++tempArrIndex, i + 1, combList); int[] newTempArr = new int[tempArr.length]; System.arraycopy(tempArr, 0, newTempArr, 0, tempArr.length - 1); tempArr = newTempArr; tempArrIndex--; } } } }
2、
package algorithm; import java.util.ArrayList; import java.util.List; /** * * @Description: 按顺序累加,与平均值相差最小的分为一组。 * 优点:解决数据、分组大时候,穷举所有组合效率低的问题。适合数据比较均匀的时候。 * 缺点:大数集中分布到一头等特殊情况分组不好。 * @author thrillerzw * @version 1.0 * @create time 2014-4-30 上午9:52:16 */ public class TestAverage { public static void main(String[] args) { List<Integer> lengthList = new ArrayList<Integer>(); lengthList.add(1); lengthList.add(2); lengthList.add(8); lengthList.add(6); lengthList.add(4); lengthList.add(10); int m = 3; List<List<Integer>> resultList = new ArrayList<List<Integer>>(); if (lengthList.size() < m) { buildResultList(resultList, lengthList); } else { int[] pointArr = findSplitPoint(lengthList, m); buildResultList(resultList, lengthList, pointArr); } System.out.print("resultList=" + resultList); } private static int[] findSplitPoint(List<Integer> lengthList, int m) { int totalNum = 0; for (int i = 0; i < lengthList.size(); i++) { totalNum += lengthList.get(i); } //平均值 double average = (double) totalNum / (double) m; System.out.println("average=" + average); int groupNum = 0; int[] pointArr = new int[m - 1]; int pointArrIndex = 0; double minDiffSum = -1; int i = 0; for (; i < lengthList.size(); i++) { int num = lengthList.get(i); //按顺序累加 groupNum += num; double curDiffSum = Math.abs(groupNum - average); int surplusGroupNum = m - 1 - pointArrIndex; int surplusDataNum = lengthList.size() - i; int differNum = surplusDataNum - surplusGroupNum; if (differNum > 0) { //当前累加 与平均值的距离 < 上次累加与平均值的距离 if (curDiffSum < minDiffSum || minDiffSum == -1) { minDiffSum = curDiffSum; } else { //保存切分点 pointArr[pointArrIndex] = i; if (pointArrIndex == m - 2) { break; } pointArrIndex++; groupNum = num; minDiffSum = Math.abs(num - average); } } else { //简单解决大数分布到头尾,不够分组的情况。把末尾的每个值单独分为一组。 pointArr[pointArrIndex++] = i; int point = i + 1; for (int j = 0; j < surplusGroupNum - 1; j++) { pointArr[pointArrIndex++] = point++; } break; } } return pointArr; } static void buildResultList(List<List<Integer>> resultList, List<Integer> dataList) { for (int i = 0; i < dataList.size(); i++) { List<Integer> list = new ArrayList<Integer>(); list.add(dataList.get(i)); resultList.add(list); } } static void buildResultList(List<List<Integer>> resultList, List<Integer> dataList, int[] resultArr) { if (resultList == null || dataList == null || resultArr == null) { return; } int j = 0; int maxJ = 0; for (int i = 0; i <= resultArr.length; i++) { if (i == resultArr.length) { maxJ = dataList.size(); } else { maxJ = resultArr[i]; } List<Integer> list = new ArrayList<Integer>(); for (; j < maxJ; j++) { list.add(dataList.get(j)); } resultList.add(list); } } }