6

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.

amit
  • 175,853
  • 27
  • 231
  • 333
aqjune
  • 478
  • 1
  • 3
  • 17
  • Can you please post a short example? – Tudor Aug 26 '12 at 07:06
  • 1
    You need L >= 2, for L >= 1, you can just return [i,i] where i is the maximum index – barak1412 Aug 26 '12 at 07:10
  • 1
    @barak1412: I believe he means `L` is a parameter given to the algorithm dynamically. – amit Aug 26 '12 at 07:19
  • I didn't understand it that way. He better give some example – barak1412 Aug 26 '12 at 07:26
  • 5
    An O(N) algorithm is reported by Goldwasser et al. in http://arxiv.org/abs/cs/0207026. You can download a pdf of the paper. You can also find an O(N*logL) one here: http://www.csie.ntu.edu.tw/~kmchao/seq04spr/jcss.pdf – Tudor Aug 26 '12 at 07:55
  • @barak1412 The length of the interval should be more than L. and L is more than 1. Therefore, if L is given as 3, then the interval can be longer than 3. – aqjune Aug 26 '12 at 08:38
  • For an example, if 1 5 6 2 9 and L = 2 is given as an input, then [6 2 9] is the answer. – aqjune Aug 26 '12 at 08:51
  • I think @Tudor gave me the answer...Thanks – aqjune Aug 26 '12 at 08:51

1 Answers1

10

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.

RoBa
  • 418
  • 3
  • 6
  • +1 This does not sink in in the first reading, but you have actually explained it well. Also, reading the answer along with this link helped me : https://activities.tjhsst.edu/sct/lectures/1112/binary102111.pdf – pyrometer Sep 30 '12 at 00:48
  • Why is `sumB[0] = 0` ? I tried implementing the solution and I think sumB[0] should be assigned B[0]. Could you please clarify this ? – pyrometer Sep 30 '12 at 11:11