Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window.
Implement the MovingAverage
class:
MovingAverage(int size)
Initializes the object with the size of the window size
.double next(int val)
Returns the moving average of the last size
values of the stream.Example 1:
MovingAverage m = new MovingAverage(3);
m.next(1); // return 1.0
m.next(10); // return (1 + 10) / 2 = 5.5
m.next(3); // return (1 + 10 + 3) / 3 = 4.66667
m.next(5); // return (10 + 3 + 5) / 3 = 6.0
Constraints:
1 <= size <= 1000
-105 <= val <= 105
104
calls will be made to next
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The goal is to find the average of the last few numbers we've seen. The brute force approach calculates the average every time we receive a new number by re-examining all the previous numbers within the specified window.
Here's how the algorithm would work step-by-step:
class MovingAverage:
def __init__(self, size_of_window):
self.size_of_window = size_of_window
self.numbers_in_window = []
def next(self, value_to_add):
self.numbers_in_window.append(value_to_add)
# Ensure the size of the window does not exceed the specified size
if len(self.numbers_in_window) > self.size_of_window:
self.numbers_in_window.pop(0)
# Calculate the current sum of numbers in the window
current_sum = 0
for number in self.numbers_in_window:
current_sum += number
# Calculating average based on elements in the window
return current_sum / len(self.numbers_in_window)
We need to keep track of a running average as new numbers come in. The trick is to avoid recalculating the entire average each time. We only need to adjust the average based on the new number and the oldest number that is no longer part of the window.
Here's how the algorithm would work step-by-step:
class MovingAverage:
def __init__(self, size):
self.window_size = size
self.number_queue = []
self.current_sum = 0.0
def next(self, value):
self.number_queue.append(value)
self.current_sum += value
# Remove the oldest element when exceeding window size.
if len(self.number_queue) > self.window_size:
self.current_sum -= self.number_queue.pop(0)
# Calculate average based on elements in the window.
return self.current_sum / len(self.number_queue)
Case | How to Handle |
---|---|
Size is zero | Return 0 or throw an exception, as a moving average with a window of size 0 is undefined. |
Size is negative | Throw an IllegalArgumentException since a negative window size is not meaningful. |
Stream contains very large positive and negative integers, causing overflow of the sum | Use long data type to store the sum or consider using a different approach that avoids storing the entire sum, like Kahan summation if high precision is required. |
Stream contains floating point numbers that result in floating point precision errors when calculating average | Use double for calculations, be aware of potential precision loss, and handle comparisons carefully by using tolerances if needed. |
The data stream contains only a few values such that the number of elements seen is less than size | Calculate the average based on the number of elements seen so far, returning the sum of elements seen / the number of elements seen. |
Maximum integer values in the stream are close to Integer.MAX_VALUE | Check for overflow during summation and either throw an exception or use long to avoid it. |
The input stream has a very large number of integers, and the size is also very large, potentially leading to high memory usage | Use a data structure with fixed memory size like a circular queue or a linked list where oldest data is removed. |
size is larger than the number of elements in stream | Return the average of all available elements or throw an exception. |