Sorry if I wrote too much. I tried to be very detailed so I could find my own answer while describing the problem (the solution, and how I got there), and yet ,if I didn't, not leaving doubts to the reader. I don't want the problem to be solved by anyone else, just get a few pointers and where should I be looking to improve my solution, if it is possible.
I am open to discard the approach if it isn't the right one, but I am also fancy for making this approach pass 100%, if it is possible, and if it makes sense and is suitable in an effort-quality relationship. If my idea is bad, I don't mind being told and follow another one, but again, please don't show me code or the "right answer", I can google it myself or find it here in SO.
The exercise goes like this:
A non-empty array A consisting of N integers is given. Array A represents numbers on a tape.
Any integer P, such that 0 < P < N, splits this tape into two non-empty parts:
A[0], A[1], ..., A[P − 1] and A[P], A[P + 1], ..., A[N − 1].
The difference between the two parts is the value of:
|(A[0] + A[1] + ... + A[P − 1]) − (A[P] + A[P + 1] + ... + A[N − 1])|
In other words, it is the absolute difference between the sum of the first part and the sum of the second part.
For example, consider array A such that:
A[0] = 3 A[1] = 1 A[2] = 2 A[3] = 4 A[4] = 3
We can split this tape in four places:
P = 1, difference = |3 − 10| = 7
P = 2, difference = |4 − 9| = 5
P = 3, difference = |6 − 7| = 1
P = 4, difference = |10 − 3| = 7
Write a function:
class Solution { public int solution(int[] A); }
that, given a non-empty array A of N integers, returns the minimal difference that can be achieved.
For example, given:
A[0] = 3 A[1] = 1 A[2] = 2 A[3] = 4 A[4] = 3
the function should return 1, as explained above.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [2..100,000]; each element of array A is an integer within the range [−1,000..1,000].
As stated in the title, my solution is not that great (66% in performance; 85% in correctness; 76% as a total score).
This is the approach I used yesterday:
accumulate from the left and the right side of the array received, and check which side would be smaller after adding the next one to the right of the left side, or the nearest to the left of the right side of the array.
Graphically, the idea was sort of making two trains: first the locomotives (head and tail of the array, respectively) of each side, and then add to each locomotive the train wagons (if any, and if it corresponded to), and make both trains crash. I was sort of "adding wagons to a train, only if the other train was bigger than the one I added a wagon to last".
The code I wrote didn't work that well, because I needed to find the smallest difference I could between the two partitions of the array.
but I got several errors from it: with negative numbers mixed with non-negative ones, two elements arrays, etc, and even worse results, (like 65% total score).
The idea is similar to the one I followed today:
Accumulate from the left and the right side, and check if the difference between the left and the right trains was smaller after adding a wagon to the left, or to the right. In this approach I concentrated in the "difference between the two trains, and not in adding a wagon if the other one was bigger and find an equilibrium".
Anyways, I got errors in:
- small_random: random small, length = 100: WRONG ANSWER, got 269 expected 39
- large_ones: large sequence, numbers from -1 to 1, length = ~100,000: WRONG ANSWER, got 228 expected 0; WRONG ANSWER, got 147 expected 1. (possible overflow?)
- large_random random large, length = ~100,000: WRONG ANSWER, got 202635 expected 1; WRONG ANSWER, got 34394 expected 2
All the other tests were fine. This is the code I wrote:
using System;
class Solution {
public int solution(int[] A)
{
int N = A.Length, P;
if (N == 0)
{
P = 0;
}
else
{
P = findTapeEquilibrium(A, N);
}
return P;
}
private static int findTapeEquilibrium(int[] A, int N)
{
int I = 0, J = N - 1;
if( N > 0 )
{
int leftP = A[I++], rightP = A[J--];
bool AIsPair = N - 1 % 2 == 0;
while((!AIsPair && J - I >= 0) || (AIsPair && J - I >= 1))
{
if (Math.Abs((leftP+A[I])-rightP) <= Math.Abs(leftP-(rightP+A[J])))
{
leftP += A[I++];
}
else
{
rightP += A[J--];
}
}
return Math.Abs(leftP - rightP);
}
return 0;
}
}