3

This problem rephrases an interview question. Since this original problem seems too hard to me I am trying to solve a simpler one: how to process an integer array to find an average of any sub-array in constant time. Obviously, we can process all sub-arrays in O(n^2). Are there better solutions?

Svante
  • 50,694
  • 11
  • 78
  • 122
Michael
  • 41,026
  • 70
  • 193
  • 341
  • Straightforward solution with iterating over sub-array to find an average, won't it have `O(n)`? Why `O(n^2)`? – Snowbear Mar 04 '11 at 15:12
  • You could pre-process by calculating the average of *every possible* subarray...then it's O(1) to just look up the answer. You never said anything about memory... :) – Michael McGowan Mar 04 '11 at 15:15
  • 2
    @Snowbear: To precompute the averages of all aubarrays would be O(n^2). – Sven Marnach Mar 04 '11 at 15:15
  • Is the array supposed to be dynamic? i.e. you can update the array after the pre-process step? –  Mar 04 '11 at 15:52
  • Btw, the sole comment to the page you linked has the answer! –  Mar 04 '11 at 16:59

2 Answers2

13

For the 1d case: compute the cumulative sums of the array, i. e. given array a, define b by

b[0] = a[0];
for (int i = 1; i < n; ++i)
    b[i] = b[i - 1] + a[i];

To compute any average of a subarray, compute the difference of the cumultaive sum corrseponding to the end index and the one corresponding to the start index, and divide by the number of entries in the subarray. For example for the range from i+1 to j, do

average = (b[j] - b[i]) / (double)(j - i);

The same thing works in two dimensions by computing cumulative sums along the two axes.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • your `j` index is exclusive. I would make it inclusive and it will lead to `average = (b[j] - b[i] + a[i]) / double(j - i + 1)` – Snowbear Mar 04 '11 at 15:23
  • @Snowbear: No, my `i` is exclusive. Actually, it would be better to increase the lentgth of `b` to `n+1` and have `0` as first entry. The current version would need special-casing for subarrays containing the 0th entry. The answer is about the basic algorithm, though, so I leave these details out :) – Sven Marnach Mar 04 '11 at 15:27
1

I would use index zero of each subarray (or a new single-dimension array of the length of the first dimension of the jagged array) to store the average, and compute that average while elements are added to the array. You can compute an average of N+1 items, given an average of N items and the +1 item, in constant time by weighting the existing average by the N items composing it. That means populating the array is still linear, and once populated you have the average in indexed memory (effectively constant-time retrieval).

EDIT: The constant-time average method isn't just "pretty close"; it can be mathematically proven that the average of N items multiplied by N, plus another item, divided by N+1, is exactly equal to the average of N+1 items in the general case. The average of a set S, multiplied by its cardinality N, equals the sum of the set S, so for any nonempty set S of cardinality N:

avg(S) = sum(S) / count(S)
S' = S + {X}
avg(S') = sum(S') / count(S')
        = (sum(S) + X) / count(S')
        = ((avg(S) * N) + X) / count(S') //QED

EDIT AGAIN: Oops: my solution is for a multi-dimensional jagged array. OK, no biggie. In this case, I would create an array containing the cumulative sum for each element of all elements from the first to the current. Then, to calculate the average of any contiguous sub-array, subtract the cumulative sum of the element before the beginning index (or zero if beginning from the first index) from the cumulative sum of the ending index, and divide by the difference between the beginning and ending indexes plus 1.

... which is Sven's answer.

KeithS
  • 70,210
  • 21
  • 112
  • 164
  • Can you find the average of _any_ sub-array in O(1) time using this? –  Mar 04 '11 at 16:58
  • Oops. I was reading the question as pertaining to a jagged array, where you were looking to get the average of one "sub-array" (the second dimension elements) of the jagged array. – KeithS Mar 04 '11 at 17:08