编程之美2.18学习笔记
2011-08-14 11:45 MichaelYin 阅读(544) 评论(0) 编辑 收藏 举报解题过程中没有使用书上提供的动态规划的算法,在这里把解题思路写一下。
题目是这样的,有个包含2n个元素的无序数组,现在用算法将这个数组进行分割,使得两个子数组的和最相近
我们首先来想像将数组分割后的情况,假设分割后的两个数组分别为A和B,A[0]和B[0]之间肯定是存在一个差值的,假设我们用A[0]-B[0],得到的值加上A[1]-B[1],这样最后得到的值的绝对值肯定是所有情况里面最小的,因为最后得到的绝对值其实就是两个数组的和的差值。
现在我们已经隐隐感觉到,其实两个元素之间的差值是我们可以拿来用的一个条件。我们只需要保证差值的绝对值为最小,这样得到的两个数组就是我们所求的结果了。然后还有一个问题,两个数组对应元素之间的差值是不一样的。比如A[0]-B[0]的差值是1,A[1] –B[1]的差值可能是99,我们需要一种策略来保证我们在计算这个差值的绝对值一定是最小。借鉴一下权重的思想,我们需要把本来差值绝对值最大的那一组A和B对应的元素放到前面去,然后依次排序,这样得到的相当于就是权重一个从大到小的顺序,我们遍历的时候就能够得到正确的结果,不至于前面出现了很多小的差值,然后因为后面出现了一个很大的差值,(比如99)使得得到的结果错误。
下面完整的将一遍解题思路,首先将原来的数组进行排序,排序是能够使得元素之间的差值之和最小(但是写这篇博客的时候我觉得这一步不是必须的,因为我需要的是差值信息,由于时间有限,就还是按照我以前的思路讲了)。排序完成之后我将元素按照排序的顺序放到两个数组subArray1和subArray2中去,这里subArray1的每个元素都会小于等于对应的subArray2元素。在遍历放到subArray1和subArray2的时候顺便将两者的差值信息专门用subSub数组放起来。
现在我们就有了三个数组,两个是元素,一个是元素对应的差值的信息,但是差值信息由权重的问题,考虑到我上面说的,我们需要将最大的差值放到前面去,这样在这里需要对subSub进行排序,需要注意的是,排序移动元素的时候,subArray1和subArray2的元素也需要进行相对应的移动。
到这里基本的东西都准备好了,然后就是一个for循环,对每个差值进行比较,原则就是一个,保证绝对值最小,如果需要将差值加法转换为减法运算,只需要调换subArray1和subArray2对应的元素就行了。这样遍历之后就能保证求出的差值的绝对值最小了。
下面贴出我试验的代码
public static void main(String[] args) { // TODO Auto-generated method stub
// 初始排序没有写,为了快速解题就直接是写的已经排好了的数组 int[] testArray = new int[] { 1, 3, 5, 6, 7, 8, 9, 11, 17, 20 }; Test218(testArray); } public static void Test218(int[] array) { // 数组用来存放结果 int[] subArray1 = new int[array.length / 2]; int[] subArray2 = new int[array.length / 2]; // 存放差值 int[] subSub = new int[array.length / 2]; for (int i = 0, j = 0; i < array.length; i = i + 2, j++) { // 将两个数分别放到两个数组中去,同时计算两个数的差值,放到subSub数组中 subArray1[j] = array[i]; subArray2[j] = array[i + 1]; subSub[j] = array[i + 1] - array[i]; } Sort(subArray1, subArray2, subSub); int sum = subSub[0]; // 对subSub进行遍历 for (int i = 1; i < subSub.length; i++) { // 求绝对值 if (Math.abs(sum - subSub[i]) < Math.abs(sum + subSub[i])) { // 调换 swap(subArray1, subArray2, i, i); sum = sum - subSub[i]; } else { sum = sum + subSub[i]; } } for (int i : subArray1) { System.out.print(i + " "); } System.out.println(); for (int i : subArray2) { System.out.print(i + " "); } } // 根据subSub数组中的差值进行快速排序,确保最大的差值放在最前面 public static void Sort(int[] subArray1, int[] subArray2, int[] subSub) { // 先用冒泡,可以用快排优化 for (int i = 0; i < subSub.length - 1; i++) for (int j = i + 1; j < subSub.length; j++) { if (subSub[j] > subSub[i]) { // 三个数组中的元素都需要进行调换 swap(subArray1, subArray1, i, j); swap(subArray2, subArray2, i, j); swap(subSub, subSub, i, j); } } } public static void swap(int[] array1, int[] array2, int i, int j) { int temp = array1[i]; array1[i] = array2[j]; array2[j] = temp; }