给定一组硬币,每个硬币都有一些价值。阵列大小为N.你可以改变任何硬币的值,除了第一枚和最后一枚硬币。您可以将ith硬币的值更改为总和的一半 第(i-1)和第(i + 1)个硬币的值,但是这样做需要满足两个条件。
(1)(i-1)和(i + 1)硬币的价值应该是均匀的
(2)如果第j个硬币的值在第i个硬币的值之后改变则j应该大于i
现在你的任务是最大化数组硬币前半部分和数组硬币下半部分值的总和之间的绝对差值。如果数组大小为奇数则忽略中间元素。
任何人都可以建议我找到答案。
任务是找到最大绝对差异。
我的算法: 1.找到左半部分和右半部分的总和 2.如果是左半部分>右半部分通过进行操作最大化左半部分并缩小左半部分,但我没有给出正确答案。
PS:我前一周参加了一次面试。在那里被问到我无法弄清楚这种方法。答案 0 :(得分:0)
我无法想到比蛮力更复杂的算法。您应该尝试所有可能的事情并返回最佳结果。我推荐一种递归方法。编写一个递归函数,它将输入列表和索引作为参数。该函数尝试更改驻留在该索引上的数字,并返回最佳结果。最后你应该打印出最好的结果。这听起来很复杂,但在行动中它相当容易。看看这段代码:
def func(input_list, index):
# if we have reached the end of the list
# we compute the result and return it
L = input_list[:]
if index == len(L):
# return absolute difference of the two halves
return abs ( sum(L[:len(L)/2]) - sum(L[int(len(L)/2.0 + 1):]) )
#result of not changing this item
no_change = func(L, index+1)
#check if it is possible to change this item
change = 0
if index-1 >= 0 and index+1 < len(L) and L[index-1]%2==0 and L[index+1]%2==0:
#result of changing this item if possible
L[index] = (L[index-1] + L[index+1])/2
change = func(L, index+1)
#return the maximum result of changing and not changing
best = max(no_change, change)
return best
L = [10, 4, 22, 8, 64]
print func(L, 0)
打印
93
获取[10, 4, 22, 43, 64]
但请记住,这种方法效率低,不适合大量投入。
答案 1 :(得分:0)
蛮力算法可以进行一些优化。
我们可以使算法在每个索引处存储从右边的所有数据计算的可能总和。这些信息将在递归递归过程中填写。
示例:为了简化,我只考虑最大化前半部分和最小化后半部分。
[4, 1, 8, 2, 4, 1, 4]
算法将深度优先于数组的最后一个元素,然后在那里存储最佳总和,只考虑右边的内容。由于右边没有任何东西,总和是4.但是当我们想要最小化时,我们切换符号。所以我们存储这样的东西:
[4, 1, 8, 2, 4, 1, 4]
-4
然后我们回溯。我们目前有两种可能性:我们将1保持原样,或者我们使用周围值的平均值(即4):
[4, 1, 8, 2, 4, 1, 4]
-4
-5
[4, 1, 8, 2, 4, 4, 4]
-4
-8
值-5和-8都将存储在散列中,因此对于值1,我们可以找到-5,对于值4,我们可以找到-8。
在算法的某一点,我们将尝试在第二个数组元素(而不是1)处使用值6,然后再次递归。当我们到达一个但是最后一个元素时,我们发现可能的值再次为1或4(如果左侧没有其他任何改变),所以我们不必更深入地进行说明:我们可以阅读从我们在该索引处维护的哈希值求和。
这个系统可以为更大的数组带来大量的节省,确保算法在真正需要时才会更深入地进行递归。显然,它在空间方面是有代价的。
然后整个算法可以第二次执行,但随后交换符号。在这两个结果中,采取了最佳解决方案,使绝对值最大化。
通过将可能更改的元素值作为函数参数传递,我们可以避免创建多个数组,并且只使用输入数组。另一方面,在每个索引处创建的哈希需要一些空间。
以下是JavaScript中的算法,其中我没有使用任何花哨的功能,因此应该很容易理解:
function getMaxSum(a) {
// Index of the element in the middle. If integer,
// the element at this index will not play a role in any sum:
var mid = (a.length-1)/2;
// Two results, one that maximises the left sum and minimises the right sum
// The other minimises the left and maximises the right:
var result, result2, b;
function recurse(prevVal, index, sign, hash = []) {
var val, nextVal, sum, result, avg;
val = a[index];
if (index >= a.length-1) {
// At the last element there are no choices left:
return { sum: -sign*(prevVal+val), nextVal: val, hash: [] };
}
if (!hash[index]) hash[index] = [];
nextVal = a[index+1];
result = { sum: -Infinity, nextVal: 0, hash: hash[index] };
// Loop through the 2 possibilities (in general): take value as is, or
// take the average of previous and next value:
while (true) {
// If the result from this position onward is not know, calculate
// it via a recursive call:
if (!hash[index][val]) hash[index][val] = recurse(val, index+1, sign, hash);
// Add the previous value to the best sum at this point, using the appropriate sign,
// and store the result in a hash table, for future reference:
sum = hash[index][val].sum + (index-1 > mid ? -1 : index-1 < mid ? 1 : 0) * sign * prevVal;
if (sum > result.sum) {
result.sum = sum;
result.nextVal = val;
}
if (prevVal % 2 || nextVal % 2 || (avg = (prevVal + nextVal)/2) === val) break;
val = avg;
}
return result;
}
// Calculate both results
result = recurse(a[0], 1, 1, []);
result2 = recurse(a[0], 1, -1, []);
// Pick the best one.
if (Math.abs(result2.sum) > Math.abs(result.sum)) result = result2;
// Rebuild the array corresponding to the best result:
b = [a[0]];
while (result) {
b.push(result.nextVal);
result = result.hash[result.nextVal];
}
return b;
}
// Sample data
var a = [4, 1, 8, 2, 4, 1, 4];
console.log(' input: ' + a);
// Apply algorithm
var b = getMaxSum(a, 1);
// Print result
console.log('result: ' + b);