I have a sorted array of integers of size n. These values are not unique. What I need to do is
: Given a B, I need to find an i<A[n] such that the sum of |A[j:1 to n]-i| is lesser than B and to that particular sum contribute the biggest number of A[j]s. I have some ideas but I can’t seem to find anything better from the naive n*B and n*n algorithm. Any ideas about O(nlogn) or O(n) ?
For example: Imagine
A[n] = 1 2 10 10 12 14 and B<7 then the best i is 12 cause I achieve having 4 A[j]s contribute to my sum. 10 and 11 are also equally good i’s cause if i=10 I got 10 – 10 + 10 – 10 +12-10 + 14-10 = 6<7
I think you can do it in O(n) using these three tricks:
CUMULATIVE SUM
Precompute an array C[k] that stores sum(A[0:k]).
This can be done recursively via C[k]=C[k-1]+A[k] in time O(n).
The benefit of this array is that you can then compute sum(A[a:b]) via C[b]-C[a-1].
BEST MIDPOINT
Because your elements are sorted, then it is easy to compute the best i to minimise the sum of absolute values. In fact, the best i will always be given by the middle entry.
If the length of the list is even, then all values of i between the two central elements will always give the minimum absolute value.
e.g. for your list 10,10,12,14 the central elements are 10 and 12, so any value for i between 10 and 12 will minimise the sum.
ITERATIVE SEARCH
You can now scan over the elements a single time to find the best value.
Keep track of the largest value for e-s seen which has a score < B and this is your answer.
This loop can go around at most 2n times so it is O(n).
The score for A[s:e] is given by sum |A[s:e]-A[(s+e)/2]|.
Let m=(s+e)/2.
and we can compute the sums in this expression using the precomputed array C[k].
EDIT
If the endpoint must always be n, then you can use this alternative algorithm:
PYTHON CODE
Here is a python implementation of the algorithm: