代码改变世界

编程之美2.18学习笔记

2011-08-14 11:45  MichaelYin  阅读(529)  评论(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;
	}