We need to design a system that, upon receiving a new element in a stream, can compute the average of the last N elements in O(1) time. For instance, if the stream is updated with 3 after receiving 0, the moving average would be calculated as (-3+0+3)/3 = 0.0.
To address this, let’s define a class with two methods allowing us to add a number to the moving average and retrieve the average in O(1) time:
This is a classical sliding window problem, where we need to compute the sum of a sliding window of size N. The average is then simply sliding_sum/N.
To implement the sliding sum, we can use a circular buffer of size N to hold the window. Each time we encounter a new element, we append it to the buffer until it is full. Once the buffer is full, we slide the head of the window by one position to the right, i.e., increment by one. As it’s a circular buffer, the head can be incremented using head=(head+1)%N. When a new element arrives, the free slot for it will be the previous slot of the head in the circular buffer, i.e., empty_slot=(N+head-1)%N. The following figures illustrate this concept:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
window of size 5 using circular buffer
free_slot head
| |
v v
|__|__|__|__|__|
free_slot head
| |
v v
|__|__|__|__|__|
head free_slot
| |
v v
|__|__|__|__|__|