PROBLEM
A zero-indexed array A consisting of N integers is given. An equilibrium index of this array is any integer P such that 0 ≤ P < N
and the sum of elements of lower indices is equal to the sum of elements of higher indices.
A[0] + A[1] + ... + A[P−1] = A[P+1] + ... + A[N−2] + A[N−1].
Sum of zero elements is assumed to be equal to 0. This can happen if P = 0
or if P = N−1
.
Range of N: [0 ... 100,000]
.
Elements Range: [−2,147,483,648 ... 2,147,483,647]
.
Complexity: worst-case time O(N)
MY 5-MIN SOLUTION
This is the intuitive solution by computing the formula performance is O(N^2)
as it sums the all array for each iteration and it doesnt work for large entries.
def solution(A):
result = []
for i in xrange(len(A)):
if sum(A[:i]) == sum(A[i+1:]):
result.append(i)
if result == []:
return -1
return result
BEST SOLUTION
This solution is O(N)
. Can someone explain the logic behind this solution.
def equi(A):
result = []
x=1
i=1
r=sum(A)
for e in A:
i-=1
r-=2*e
if -e==r:
result.append(-i)
return result
I believe the solution you posted does not work at all, and it's very difficult to understand anyways. So here's my take on it:
Basically, instead of recalculating sum(left side) and sum(right side) on every iteration of your loop, you can figure them out with simple math.
State at some point, with an array of size n:
Now let's go forward one step and check what we should have:
Now, what did change?
It may be confusing, but it should be plain to see that there is some way to get the sums of the left and right side at any point by adding and substracting to your previous values.
The O(n) solution is a bit too clever and somewhat obfuscated, but it works just fine. I've rewritten it with meaningful variable names and moved some things around to make it more clear how it works.
Now an explanation. Let
When
A[0]
is removed fromright
and added toleft
,difference
goes down by2*A[0]
. IfA[1]
is then moved fromright
toleft
,difference
goes down by2*A[1]
. Whenever elementA[p]
is moved,difference
goes down by2*A[p]
. That explains lines 4 and 5.Now, at equilibrium index P, we have:
or,
and
If we move
A[P]
fromright
toleft
,difference
goes down by2*A[P]
, and nowThat is, when an equilibrium point is moved from
right
toleft
,difference
goes fromA[P]
to-A[P]
. So, ifdifference == -A[P]
, thenP
is an equilibrium index. That explains the test in line 6.Note,
left
andright
aren't really needed for the algorithm. They were just used for the explanation.Another approach would be as follows:
Consider what we know at the beginning of our quest - we know the length of the input i.e.
len(A)
, we know the sum of the input i.e.sum(A)
, we also know that no previous sum has been calculated. Thus these become our initial variables e.g.Next let's consider what happens per iteration. We declare a variable e.g.
rem
which is the value of(sumA - prevSum -A[i])
. In essence at each iteration we want to remove the previous sum(prevSum
orleftSum
) from the sum of the array and also remove the present value.Then we check if
rem == prevSum
. If this is True we return the index, if false we repeat this cycle till all elements in the array have been checked at this point we return a Falsy value.The code for this is available here