我的问题是关于 CodeFu 练习题(2012 年第 2 轮问题 3)。它基本上归结为将整数数组分成两个(几乎)相等的一半,并返回两者之间的最小可能差异。我在下面包含了问题描述。正如评论中所指出的,这可以描述为一个平衡分区问题,这是一个动态规划领域的问题。
现在已经讨论了很多类似的问题,但我无法为这个特定的问题找到有效的解决方案。问题当然是,对于蛮力搜索(至少在使用递归时),要遍历的可能组合的数量很快就会变得太大。我有一个递归解决方案,它适用于除最大问题集之外的所有问题。我尝试添加一些优化以提前停止递归,但性能仍然太慢,无法在 CodeFu 允许的 5 秒最大值内解决一些最大长度(30)的数组。任何有关如何改进或重写代码的建议都将受到欢迎。我也很想知道它是否有助于制作迭代版本。
更新:在这个很好的网站上有一个关于平衡分区问题的理论讨论,它很好地说明了如何以动态方式进行和解决这个问题。这确实是我所追求的,但我不知道如何将理论付诸实践。电影中提到可以“使用反向指针的旧技巧”找到两个子集合中的元素,但我不明白如何。
问题
你和你的朋友有许多不同数量的硬币。您需要将硬币分成两组,以使这些组之间的差异最小。
例如,大小为 1,1,1,3,5,10,18 的硬币可以拆分为: 1,1,1,3,5 和 10,18 1,1,1,3,5,10 和 18 或 1 ,1,3,5,10 和 1,18 第三种组合是有利的,因为在这种情况下,组之间的差异仅为 1。约束:硬币将具有 2 到 30 个元素,包括硬币的每个元素将介于 1 和100000 含
返回值:将硬币分成两组时可能的最小差异
注意:CodeFu 规则规定在 CodeFu 的服务器上执行时间不得超过 5 秒。
主要代码
Arrays.sort(coins);
lower = Arrays.copyOfRange(coins, 0,coins.length-1);
//(after sorting) put the largest element in upper
upper = Arrays.copyOfRange(coins, coins.length-1,coins.length);
smallestDifference = Math.abs(arraySum(upper) - arraySum(lower));
return findSmallestDifference(lower, upper, arraySum(lower), arraySum(upper), smallestDifference);
递归代码
private int findSmallestDifference (int[] lower, int[] upper, int lowerSum, int upperSum, int smallestDifference) {
int[] newUpper = null, newLower = null;
int currentDifference = Math.abs(upperSum-lowerSum);
if (currentDifference < smallestDifference) {
smallestDifference = currentDifference;
}
if (lowerSum < upperSum || lower.length < upper.length || lower[0] > currentDifference
|| lower[lower.length-1] > currentDifference
|| lower[lower.length-1] < upper[0]/lower.length) {
return smallestDifference;
}
for (int i = lower.length-1; i >= 0 && smallestDifference > 0; i--) {
newUpper = addElement(upper, lower[i]);
newLower = removeElementAt(lower, i);
smallestDifference = findSmallestDifference(newLower, newUpper,
lowerSum - lower[i], upperSum + lower [i], smallestDifference);
}
return smallestDifference;
}
数据集
这是一个需要很长时间才能解决的集合的示例。
{100000,60000,600,600,600,60000,600,600,600,60000,60000,60000,60000,60000,600,600,600,600,600,600,600,60000,600,600,60000,60000,600,60000,600,600,600,60000,600,600,600,60000,600,600,600,60000,60000 ,60000,60000, 60000,60000,60000}
如果您想要完整的源代码,我已将其放在Ideone上。