Subinterval of length >= k in an array, with maximum average [duplicate] - arrays

From an integer array A[N], I'd like to find an interval [i,j] that has a maximized average (A[i] + A[i + 1] + .. + A[j]) / (j - i + 1).
The length of the interval (j - i + 1) should be more than L.(L >= 1)
What I thought was to calculate an average for every i ~ j, but it is too slow to do like this.(N is too big)
Is there an algorithm faster than O(N^2)? Or I'd like to know whether there exists a randomized method for that.

There is an O(N*logC) algorithm, where C is proportional to the maximum element value of the array. Comparing with some more complicated algorithms in recent papers, this algorithm is easier to understand, and can be implemented in a short time, and still fast enough in practical.
For simplicity, We assume there is at least one non-negative integers in the array.
The algorithm is based on binary search. At first, we can find that the final answer must be in the range [0, max(A)], and we half this interval in each iteration, until it is small enough (10-6 for example). In each iteration, assume the available interval is [a,b], we need to check whether the maximum average is no less than (a+b)/2. If so, we get a smaller interval [(a+b)/2, b], or else we get [a, (a+b)/2].
Now the problem is: Given a number K, how to check that the final answer is at least K?
Assume the average is at least K, there exist some i, j such that (A[i] + A[i+1] + ... + A[j]) / (j - i + 1) >= K. We multiply both sides by (j-i+1), and move the right side to left, and we get (A[i] - K) + (A[i+1] - K) + ... + (A[j] - K) >= 0.
So, let B[i] = A[i] - K, we only need to find an interval [i, j] (j - i + 1 > L) such that B[i] + ... + B[j] >= 0. Now the problem is: Given array B and length L, we are to find an interval of maximum sum whose length is more than L. If the maximum sum is >= 0, the original average number K is possible.
The second problem can be solved by linear scan. Let sumB[0] = 0, sumB[i] = B[1] + B[2] + ... + B[i]. For each index i, the max-sum interval which ended at B[i] is sumB[i] - min(sumB[0], sumB[1], ..., sumB[i-L-1]). When scanning the array with increasing i, we can maintain the min(sumB[0], ..., sumB[i-L-1]) on the fly.
The time complexity of the sub-problem is O(N). And we need O(logC) iterations, so the total complexity is O(N*logC).
P.s. This kinds of "average problem" belongs to a family of problems called fractional programming. The similar problems are minimum average-weighted spanning tree, minimum average-weighted cycle, etc.
P.s. again. The O(logC) is a loose bound. I think we can reduce it by some careful analysis.

Related

Finding period of a sequence

I want to solve this problem:
For a given sequence, a[0], a[1], a[2],..., a[n-1], please find "period" of the sequence.
The period is the minimum integer k (k >= 1) that satisfies a[i] = a[i+k] for all valid i, and also k is a divisor of n.
My current solution is calculating all divisor of n (this is k) and test for all k, but it takes O(n * d(n)). I think it is slow.
Is there any efficient algorithm?
Apply Z-algorithm ( here and here) to given sequence.
Then find the first position i such that
i+z[i] = n
and
n mod i = 0
If such value of i exists, it is the shortest period

Finding the smallest sum of the difference of A[i] and a constant

For an assignment I need to solve a mathmatical problem. I narrowed it down to the following:
Let A[1, ... ,n] be an array of n integers.
Let y be an integer constant.
Now, I have to write an algorithm that finds the minimum of M(y) in O(n) time:
M(y) = Sum |A[i] - y|, i = 1 to n. Note that I not just take A[i] - y, but the absolute value |A[i] - y|.
For clarity, I also put this equation in Wolfram Alpha.
I have considered least squares method, but this will not yield the minimum of M(y) but more of an average value of A, I think. As I'm taking the absolute value of A[i] - y, there is also no way I can differentiate this function to y. Also I can't just come up with any algorithm because I have to do it in O(n) time. Also, I believe there can be more correct answers for y in some cases, in that case, the value of y must be equal to one of the integer elements of A.
This has really been eating me for a whole week now and I still haven't figured it out. Can anyone please teach me the way to go or point me in the right direction? I'm stuck. Thank you so much for your help.
You want to pick a y for which M(y) = sum(abs(A[i] - y)) is minimal. Let's assume every A[i] is positive (it does not change the result, because the problem is invariant by translation).
Let's start with two simple observations. First, if you pick y such that y < min(A) or y > max(A), you end up with a greater value for M(y) than if you picked y such that min(A) <= y <= max(A). Also, there is a unique local minimum or range of minima of A (M(y) is convex).
So we can start by picking some y in the interval [min(A) .. max(A)] and try to move this value around so that we get a smaller M(y). To make things easier to understand, let's sort A and pick a i in [1 .. n] (so y = A[i]).
There are three cases to consider.
If A[i+1] > A[i], and either {n is odd and i < (n+1)/2} or {n is even and i < n/2}, then M(A[i+1]) < M(A[i]).
This is because, going from M(A[i]) to M(A[i+1]), the number of terms that decrease (that is n-i) is greater than the number of terms that increase (that is i), and the increase or decrease is always of the same amount. In the case where n is odd, i < (n+1)/2 <=> 2*i < n+1 <=> 2*i < n, because 2*i is even (thus necessarily smaller than a larger even number from which we subtract one).
In more formal terms, M(A[i]) = sum(A[i]-A[s]) + sum(A[g]-A[i]), where s and g represent indices such that A[s] < A[i] and A[g] > A[i]. So if A[i+1] > A[i], then M(A[i+1]) = sum(A[i]-A[s]) + i*(A[i+1]-A[i]) + sum(A[g]-A[i]) - (n-i)*(A[i+1]-A[i]) = M(A[i]) + (2*i-n)*(A[i+1]-A[i]). Since 2*i < n and A[i+1] > A[i], (2*i-n)*(A[i+1]-A[i]) < 0, so M(A[i+1]) < M(A[i]).
Similarly, if A[i-1] < A[i], and either {n is odd and i > (n+1)/2} or {n is even and i > (n/2)+1}, then M(A[i-1]) > M(A[i]).
Finally, if {n is odd and i = (n+1)/2} or {n is even and i = (n/2) or (n/2)+1}, then you have a minimum, because decrementing or incrementing i will eventually lead you to the first or second case, respectively. There are leftover possible values for i, but all of them lead to A[i] being a minimum too.
The median of A is exactly the value A[i] where i satisfies the last case. If the number of elements in A is odd, then you have exactly one such value, y = A[(n+1)/2] (but possibly multiple indices for it) ; if it's even, then you have a range (which may contain just one integer) of such values, A[n/2] <= y <= A[n/2+1].
There is a standard C++ algorithm that can help you find the median in O(n) time : nth_element. If you are using another language, look up the median of medians algorithm (which Nico Schertler pointed out) or even introselect (which is what nth_element typically uses).

Finding the probability that two items are compared. (hints please)

I'm attempting to solve the following problem (from Prof. Jeff Erikson's notes): Given the algorithm below which takes in an unsorted array A and returns the k-th smallest element in the array (given that Partition does what its name implies via the standard quicksort method given the pivot returned by Random (which is assumed to return a uniformly random integer between 1 and n in linear time) and returns the new index of the pivot), we are to find the exact probability that this algorithm compares the i-th smallest and j-th smallest elements in the input array.
QuickSelect(A[1..n],k):
r <-- Partition(A[1..n],Random(n))
if k < r:
return QuickSelect(A[1..r-1],k)
else if k > r:
return QuickSelect(A[r+1..n],k-r)
else:
return A[k]
Now, I can see that the probability of the first if statement being true is (n-k)/n, the probability of the second block being true is (k-1)/n, and the probability of executing the else statement is 1/n. I also know that (assuming i < j) the probability of i < r < j is (j-i-1)/n which guarantees that the two elements are never compared. On the other hand, if i==r or j==r, then i and j are guaranteed to be compared. The part that really trips me up is what happens if r < i or j < r, because whether or not i and j are compared depends on the value of k (whether or not we are able to recursively call QuickSelect).
Any hints and/or suggestions would be greatly appreciated. This is for homework, so I would rather not have full solutions given to me so that I may actually learn a bit. Thanks in advance!
As it has already been mentioned Monte Carlo method is simple solution for fast (in sense of implementation) approximation.
There is a way to compute exact probability using dynamic programming
Here we will assume that all elements in array are distinct and A[i] < A[j].
Let us denote P(i, j, k, n) for probability of comparison ith and jth elements while selecting k-th in an n-elements array.
Then there is equal probability for r to be any of 1..n and this probability is 1/n. Also note that all this events are non-intersecting and their union forms all the space of events.
Let us look carefully at each possible value of r.
If r = 1..i-1 then i and j fall into the same part and the probability of their comparison is P(i-r, j-r, k-r, n-r) if k > r and 0 otherwise.
If r = i the probability is 1.
If r = i+1..j-1 the probability is 0.
If r = j the probability is 1 and if r = j+1..n the probability is P(i, j, k, r-1) if k < r and 0 otherwise.
So the full recurrent formula is P(i, j, k, n) = 1/n * (2 + Sum for r = 1..min(r, i)-1 P(i-r, j-r, k-r, n-r) + sum for r = max(j, k)+1..n P(i, j, k, r-1))
Finally for n = 2 (for i and j to be different) the only possible Ps are P(1, 2, 1, 2) and P(1, 2, 2, 2) and both equal 1 (no matter what r is equal to there will be a comparison)
Time complexity is O(n^5), space complexity is O(n^4). Also it is possible to optimize calculations and make time complexity O(n^4). Also as we only consider A[i] < A[j] and i,j,k <= n multiplicative constant is 1/8. So it would possible to compute any value for n up to 100 in a couple of minutes, using straight-forward algorithm described or up to 300 for optimized one.
Note that two positions are only compared if one of them is the pivot. So the best way to look at this is to look at the sequence of chosen pivots.
Suppose the k-th smallest element is between i and j. Then i and j are not compared if and only if an element between them is selected as a pivot before i or j are. What is the probability that this happens?
Now suppose the k-th smallest element is after j. i and j are not compared if and only if an element between i+1 and k (excluding j) is selected as a pivot before i or j are. What is the probability that this happens?

Run time of a function

Let function f() be:
void f(int n)
{
for (int i=1; i<=n; i++)
for (int j=1; j<=n*n/i; j+=i)
printf(“*”);
}
According to my calculations, the run time in Big O method should be O(n2log n).
The answer is O(n2). Why is that?
I owe you an apology. I misread your code the first time around, so the initial answer I gave was incorrect. Here's a corrected answer, along with a comparison with the original answer that explains where my analysis went wrong. I hope you find this interesting - I think there's some really cool math that arises from this!
The code you've posted is shown here:
for (int i=1; i<=n; i++)
for (int j=1; j<=n*n/i; j+=i)
printf(“*”);
To determine the runtime of this code, let's look at how much work the inner loop does across all iterations. When i = 1, the loop counts up to n2 by ones, so it does n2 work. When i = 2, the loop counts up to n2 / 2 by twos, so it does n2 / 4 work. When i = 3, the loop counts up to n2 / 3 by threes, so it does n2 / 9 work. More generally, the kth iteration does n2 / k2 work, since it counts up to n2 / k with steps of size k.
If we sum up the work done here for i ranging from 1 to n, inclusive, we see that the runtime is
n2 + n2 / 4 + n2 / 9 + n2 / 16 + ... + n2 / n2
= n2 (1 + 1/4 + 1/9 + 1/16 + 1/25 + ... + 1/n2).
The summation here (1 + 1/4 + 1/9 + 1/16 + ...) has the (surprising!) property that, in the limit, it's exactly equal to π2 / 6. In other words, the runtime of your code asymptotically approaches n2 π / 6, so the runtime is O(n2). You can see this by writing a program that compares the number of actual steps against n2 π / 6 and looking at the results.
I got this wrong the first time around because I misread your code as though it were written as
for (int i=1; i<=n; i++)
for (int j=1; j<=n*n/i; j+=1)
printf(“*”);
In other words, I thought that the inner loop took steps of size one on each iteration rather than steps of size i. In that case, the work done by the kth iteration of the loop is n2 / k, rather than n2 / k2, which gives a runtime of
n2 + n2/2 + n2/3 + n2/4 + ...n2/n
= n2(1 + 1/2 + 1/3 + 1/4 + ... + 1/n)
Here, we can use the fact that 1 + 1/2 + 1/3 + ... + 1/n is a well-known summation. The nth harmonic number is defined as Hn = 1 + 1/2 + 1/3 + ... + 1/n and it's known that the harmonic numbers obey Hn = Θ(log n), so this version of the code runs in time O(n2 log n). It's interesting how this change so dramatically changes the runtime of the code!
As an interesting generalization, let's suppose that you change the inner loop so that the step size is iε for some ε > 0 (and assuming you round up). In that case, the number of iterations on the kth time through the inner loop will be n2 / k1 + ε, since the upper bound on the loop is n2 / k and you're taking steps of size kε. Via a similar analysis to what we've seen before, the runtime will be
n2 + n2 / 21+ε + n2 / 31+ε + n2 / 31+ε + ... + n2 / n1+ε
= n2(1 + 1/21+ε + 1/31+ε + 1/41+ε + ... + 1/n1+ε)
If you've taken a calculus course, you might recognize that the series
1 + 1/21+ε + 1/31+ε + 1/41+ε + ... + 1/n1+ε
converges to some fixed limit for any ε > 0, meaning that if the step size is any positive power of i, the overall runtime will be O(n2). This means that all of the following pieces of code have runtime O(n2):
for (int i=1; i<=n; i++)
for (int j=1; j<=n*n/i; j+=i)
printf(“*”);
for (int i=1; i<=n; i++)
for (int j=1; j<=n*n/i; j+=i*i)
printf(“*”);
for (int i=1; i<=n; i++)
for (int j=1; j<=n*n/i; j+=i*(sqrt(i) + 1))
printf(“*”);
Run time for first loop is n and Run time for second loop is (n/i)^2 (not n^2/i) because we have j+=i(not j++). So total time is as follow:
∑{i=1to n}(n/i)^2 = n^2∑{i=1to n}(1/i)^2 < 2*n^2
So time complexity is O(n^2)
From what I've learned from theory, is that the i does not affect the complexity very much. Since you have an exponential function, the log n would be neglected. Therefore, it would be considered only the big O(n2) instead of the expected O(n2log n).
Recall that when we use big-O notation, we drop constants and low-order terms. This is because when the problem size gets sufficiently large, those terms don't matter. However, this means that two algorithms can have the same big-O time complexity, even though one is always faster than the other. For example, suppose algorithm 1 requires N2 time, and algorithm 2 requires 10 * N2 + N time. For both algorithms, the time is O(N2), but algorithm 1 will always be faster than algorithm 2. In this case, the constants and low-order terms do matter in terms of which algorithm is actually faster.
However, it is important to note that constants do not matter in terms of the question of how an algorithm "scales" (i.e., how does the algorithm's time change when the problem size doubles). Although an algorithm that requires N2 time will always be faster than an algorithm that requires 10*N2 time, for both algorithms, if the problem size doubles, the actual time will quadruple.
When two algorithms have different big-O time complexity, the constants and low-order terms only matter when the problem size is small. For example, even if there are large constants involved, a linear-time algorithm will always eventually be faster than a quadratic-time algorithm. This is illustrated in the following table, which shows the value of 100*N (a time that is linear in N) and the value of N2/100 (a time that is quadratic in N) for some values of N. For values of N less than 104, the quadratic time is smaller than the linear time. However, for all values of N greater than 104, the linear time is smaller.
Take a look at this article for more details.

Given two arrays find the index k that minimizes the sum A[i]*|B[i]-B[k]|

I am given two arrays that contains natural numbers , A and B , and I need to find the index k that minimizes the sum A[i] * |B[i]-B[k]| from i=0 to n-1.
(Both arrays have the same length)
Its obviously easy to do in O(n^2) , I just calculate all sums for all k between 0 and n-1, but I need a better run time complexity.
Any ideas? Thanks!
You can do this in time O(nlogn) by first sorting both arrays based on the values in B, and then performing a single scan.
Once the arrays are sorted, then B[i]>=B[k] if i>k and B[i]<=B[k] if i<= k, so the sum can be rewritten as:
sum A[i] * abs(B[i]-B[k]) = sum A[i]*(B[i]-B[k]) for i=k..n-1
+ sum A[i]*(B[k]-B[i]) for i=0..k-1
= sum A[i]*B[i] for i=k..n-1
- B[k] * sum A[i] for i=k..n-1
+ B[k] * sum A[i] for i = 0..k-1
- sum A[i]*B[i] for i = 0..k-1
You can precalculate all of the sums in time O(n) which then lets you evaluate the target sum at every position in O(n) and select the value for k which gives the best score.
I believe I can do this is O(n log n).
First, sort the B array, applying the same permutation to the A array (and remembering the permutation). This is the O(n log n) part. Since we sum over all i, applying the same permutation to the A and B arrays does not change the minimum.
With a sorted B array, the rest of the algorithm is actually O(n).
For each k, define an array Ck[i] = |B[i] - B[k]|
(Note: We will not actually construct Ck... We will just use it as a concept for easier reasoning.)
Observe that the quantity we are trying to minimize (over k) is the sum of A[i] * Ck[i]. Let's go ahead and give that a name:
Define: Sk = Σ A[i] * Ck[i]
Now, for any particular k, what does Ck look like?
Well, Ck[k] = 0, obviously.
More interestingly, since the B array is sorted, we can get rid of the absolute value signs:
Ck[i] = B[k] - B[i], for 0 <= i < k
Ck[i] = 0, for i = k
Ck[i] = B[i] - B[k], for k < i < n
Let's define two more things.
Definition: Tk = Σ A[i] for 0 <= i < k
Definition: Uk = Σ A[i] for k < i < n
(That is, Tk is the sum of the first k-1 elements of A. Uk is the sum of all but the first k elements of A.)
The key observation: Given Sk, Tk, and Uk, we can compute Sk+1, Tk+1, and Uk+1 in constant time. How?
T and U are easy.
The question is, how do we get from Sk to Sk+1?
Consider what happens to Ck when we go to Ck+1. We simply add B[k+1]-B[k] to every element of C from 0 to k, and we subtract the same amount from every element of C from k+1 to n (prove this). That means we just need to add Tk * (B[k+1] - B[k]) and subtract Uk * (B[k+1] - B[k]) to get from Sk to Sk+1.
Algebraically... The first k terms of Sk are just the sum from 0 to k-1 of A[i] * (B[k] - B[i]).
The first k terms of Sk+1 are the sum from 0 to k-1 of A[i] * (B[k+1] - B[i])
The difference between these is the sum, from 0 to k-1, of (A[i] * (B[k+1] - B[i]) - (A[i] * (B[k] - B[i])). Factor out the A[i] terms and cancel the B[i] terms to get the sum from 0 to k-1 of A[i] * (B[k+1] - B[k]), which is just Tk * (B[k+1] - B[k]).
Similarly for the last n-k-1 terms of Sk.
Since we can compute S0, T0, and U0 in linear time, and we can go from Sk to Sk+1 in constant time, we can calculate all of the Sk in linear time. So do that, remember the smallest, and you are done.
Use the inverse of the sort permutation to get the k for the original arrays.
Here is O(NlogN) solution.
Example
A 6 2 5 10 3 8 7
B 1 5 4 3 6 9 7
1) First sort the two array to increasing of order of B. A's element is just binding with B.
After sort, we get
A 6 10 5 2 3 7
B 1 3 4 5 6 7
Since B are in order now. We have
n-1
sum A[i]|B[i]-B[k]|
i=0
k-1 n-1
=sum A[i](B[k]-B[i])+ sum A[i](B[k]-B[i])
i=0 i=k+1
k-1 n-1 k-1 n-1
=B[k](sum A[i] -sum A[i]) - (sum A[i]B[i]- sum A[i]B[i])
i=0 i=k+1 i=0 i=k+1
2) We calculate prefix sum of array A sumA=0 6 16 21 23 26 33
i=e
With sumA sum A[i] can be calcuated in O(1) time for any s and e.
i=s
For the same reason, we can calculate A[i]B[i]'s prefix sum.
So for each k, to check its value, it just take O(1) time.
So total time complexity is O(NlogN)+O(N).

Resources