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);