那天去面试,做到了一题笔试题。题目看上去很简单。具体如下:就是有一个数组,内容随机,长度不定,要求把他分成两个子数组,使得这两个子数组的和最接近(当然原题是差最小)。我给出的思路是这样的:①算出大数组和的一半A②将数组排序后取第一个值B③对数组做循环,从i=0开始,判断B是否小于等于A,如果是,则取i+1的数+B判断是否小于等于A,如果是则继续判断,直至i+1的数加上后超出A,此时子数组1即为0-i的值,剩下子数组2即为i+1以后的值。当初我也不知道对不对,总感觉思路不对,于是在答题的结尾还补了一句思路可能不对。后来结束后我去网上查了下,给出的方案大体一致,不同的是并没有对原数组进行排序。核心思想也是:在array中选取若干个元素,使得这些元素的和<=sum/2,且是最接近sum/2的元素集合。方法也有不同,网上给出的是
建一个数组:int[][]f=new int[length+1][sum/2+1]
状态方程:f[i][j]=Max(f[i-1][j-array[i]]+array[i],f[i-1][j])
解释:f[i][j]表示array中i个元素的和<=j,且是最接近j的元素集合。f[i-1][j-array[i]]表示array中i-1个元素的和最接近j-array[i],所以f[i][j]应该是[i-1][j-array[i]]+array[i]和f[i-1][j]中最大的那个。有点像0-1背包问题。
1 public class DivideArrayTest {
2
3 /**
4 * @param args
5 */
6 public static void main(String[] args) {
7 // TODO Auto-generated method stub
8 int[] array = { 1, 0, 1, 7, 2, 4 };
9 System.out.println(getMaxDiff(array));
10
11 }
12
13 /* f[i][j]表示i个元素装容量为j的背包能装的最大容量 */
14 public static int getMaxDiff(int[] array) {
15 int sum = getSum(array);
16 int length = array.length;
17 int[][] f = new int[length + 1][sum / 2 + 1];
18 for (int i = 0; i < length; i++) {
19 for (int j = 1; j <= sum / 2; j++) {
20 f[i + 1][j] = f[i][j];
21 if (array[i] <= j && f[i][j - array[i]] + array[i] > f[i][j]) {
22 f[i + 1][j] = f[i][j - array[i]] + array[i];
23 }
24 }
25 }
26 return sum - 2 * f[length][sum / 2];
27 }
28
29 public static int getSum(int[] array) {
30 int sum = 0;
31 for (int i = 0; i < array.length; i++) {
32 sum += array[i];
33 }
34 return sum;
35 }
36
37 }
说实话,不是很理解,我觉得按我的方式是否更加好一点呢?