Here's a code challenge I got. (I could not solve the challenge, I ran out of time. I rephrased the challenge language and I am trying the challenge again for personal growth & computer science knowledge)
Consider an array A of N integers. You can delete zero or more of its elements.
Then take the remaining elements and reduce to an integer S according to these rules:
- elements in even positions are added
- elements in odd positions are subtracted: e.g. S = A[0] − A[1] + A[2] − A[3] + ...
Create a function to find the maximum value of S
- When
A = [4, 1, 2, 3]
, thenS = 6
, because the function could delete the third value in A:A = [4, 1, 3]
. ThenS = 4 − 1 + 3 = 6
.- When
A = [1, 2, 3, 3, 2, 1, 5]
, thenS = 7
, because forA = [3, 1, 5]
, then S is maximizedS = 3 − 1 + 5 = 7
.- When
A = [1000000000, 1, 2, 2, 1000000000, 1, 1000000000]
, thenS = 999999998
, because forA = [1000000000, 1, 1000000000, 1, 1000000000]
, then S is maximized,S = 1000000000 - 1 + 1000000000 -1 + 1000000000 = 2999999998
You can assume that the value for S will not overflow an integer, and the length of the array (N) is under 100,000.
After giving it more thought, I tried solution function get_best
.
I wrote in Javascript, but I appreciate your advice in any language.
function get_best(A) {
// rather than modifying the original array `A`, I accumulate a new array `remaining` with only the items from `A` that I didn't "delete"
var remaining = [];
A.forEach((current_item, i) => {
var is_would_add = remaining.length % 2 == 0;
var last_taken_item = remaining[remaining.length - 1];
var next_item = A[i + 1];
if (is_would_add) {
console.log(`add: the current item ${current_item} will be added (net positive); taking the current item`);
remaining.push(current_item);
} else {
if (last_taken_item < current_item) {
console.log(`subtract: last item ${last_taken_item} added *less* than the current item ${current_item} would subtract (net negative); taking the current item instead`);
remaining.pop();
remaining.push(current_item);
} else if (next_item < current_item) {
console.log(`subtract: the next item ${next_item} would be a smaller negative than the current item ${current_item}, ignoring the current item`);
} else {
console.log(`subtract: the current item ${current_item} wont contribute to net negative, nor would the next item be a smaller choice; taking the current item`);
remaining.push(current_item);
}
}
});
return {
remaining,
reduction: remaining.reduce((accumulator, cv, ci) => {
return accumulator + ((ci % 2 == 0) ? cv : -cv);
}, 0)
}
}
[
{
input: [4, 1, 2, 3],
output: { remaining: [4, 1, 3], reduction: 6 }
},
{
input: [1, 2, 3, 3, 2, 1, 5],
output: { remaining: [3, 1, 5], reduction: 7 }
},
{
input: [1000000000, 1, 2, 2, 1000000000, 1, 1000000000],
output: { remaining: [1000000000, 1, 1000000000, 1, 1000000000], reduction: 2999999998 }
}
].forEach((example, example_index) => {
var best_output = get_best(example.input);
if (best_output.reduction !== example.output.reduction) {
console.warn(`example ${example_index + 1} failed, expected reduction is ${example.output.reduction} with expected remaining ${example.output.remaining} -- actual reduction is ${best_output.reduction} with actual remaining ${best_output.remaining}`);
} else {
console.log(`example ${example_index + 1} produced the expected result`);
}
});
Some questions:
- With the three examples given, did they find? I can't find better results. Of course, in answering this question, I must think about how my function should work. But I just want to confirm the examples aren't misleading!
- The solution above solves the above examples, but I challenge myself to find an example that my solution does not solve.
- The solution above; what's its complexity?
- what time complexity? I think it's O(N) (size of the array
A
) - what space complexity? I'm not sure how to measure this, I'll search for some resources on understanding space complexity (I will read more of my resource for learning about complexity)
- what time complexity? I think it's O(N) (size of the array
- Are there any "tricks or techniques" you can suggest to approach this challenge even if you can't offer a solution outright?
- Is there another solution? How is the solution better; does it solve more examples, and/or perform better in terms of time complexity, or space complexity? I have an idea, but I'm not sure if it's a good idea, or a better solution...
- use some kind of binary search to find the maximum value, split into left and right parts, and recursively find the maximum value of each (with constraints, like the left part must have an even number of elements, etc)