Welcome to Subscribe On Youtube
346. Moving Average from Data Stream
Description
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 windowsize
.double next(int val)
Returns the moving average of the lastsize
values of the stream.
Example 1:
Input ["MovingAverage", "next", "next", "next", "next"] [[3], [1], [10], [3], [5]] Output [null, 1.0, 5.5, 4.66667, 6.0] Explanation MovingAverage movingAverage = new MovingAverage(3); movingAverage.next(1); // return 1.0 = 1 / 1 movingAverage.next(10); // return 5.5 = (1 + 10) / 2 movingAverage.next(3); // return 4.66667 = (1 + 10 + 3) / 3 movingAverage.next(5); // return 6.0 = (10 + 3 + 5) / 3
Constraints:
1 <= size <= 1000
-105 <= val <= 105
- At most
104
calls will be made tonext
.
Solutions
This solution implements a moving average data structure that supports a method next(val)
where val
is an integer representing the next number in the data stream.
Class Initialization: __init__(self, size: int)
self.arr
: Initializes an array of lengthsize
filled with zeros. This array serves as a circular buffer to hold the lastN
values inserted, whereN
is the specifiedsize
.self.s
: Initializes the sum of numbers currently in the circular buffer to0
. This sum is used to efficiently compute the moving average.self.cnt
: A counter to keep track of the total number of values that have been inserted so far. It helps in managing the circular nature ofself.arr
and calculating the average correctly during the initial phase when the buffer is not yet full.
Method: next(self, val: int) -> float
- Circular Array Indexing:
idx = self.cnt % len(self.arr)
calculates the index at which the new value should be inserted. This calculation ensures that the array is used as a circular buffer, overwriting the oldest data points with new ones once the buffer size (size
) is exceeded. - Updating Sum: The new value
val
is added toself.s
, and the value being overwritten inself.arr
is subtracted fromself.s
. This keepsself.s
as the sum of all numbers currently in the buffer. - Inserting New Value: The new value
val
is stored in the array at the calculated indexidx
. - Incrementing Counter: The counter
self.cnt
is incremented by1
to reflect the insertion of a new data point. - Calculating and Returning Moving Average: The method returns the moving average of the last
N
values. It dividesself.s
bymin(self.cnt, len(self.arr))
to ensure the correct average is calculated:- During the initial phase (when fewer than
N
values have been inserted), it divides byself.cnt
to average only the values that have been inserted. - Once the buffer is full (
self.cnt >= N
), it divides bylen(self.arr)
(N
) to calculate the average of the lastN
values.
- During the initial phase (when fewer than
-
class MovingAverage { private int[] arr; private int s; private int cnt; public MovingAverage(int size) { arr = new int[size]; } public double next(int val) { int idx = cnt % arr.length; s += val - arr[idx]; arr[idx] = val; ++cnt; return s * 1.0 / Math.min(cnt, arr.length); } } /** * Your MovingAverage object will be instantiated and called as such: * MovingAverage obj = new MovingAverage(size); * double param_1 = obj.next(val); */
-
class MovingAverage { public: MovingAverage(int size) { arr.resize(size); } double next(int val) { int idx = cnt % arr.size(); s += val - arr[idx]; arr[idx] = val; ++cnt; return (double) s / min(cnt, (int) arr.size()); } private: vector<int> arr; int cnt = 0; int s = 0; }; /** * Your MovingAverage object will be instantiated and called as such: * MovingAverage* obj = new MovingAverage(size); * double param_1 = obj->next(val); */
-
class MovingAverage: def __init__(self, size: int): self.arr = [0] * size self.s = 0 self.cnt = 0 def next(self, val: int) -> float: idx = self.cnt % len(self.arr) # circular array self.s += val - self.arr[idx] self.arr[idx] = val self.cnt += 1 return self.s / min(self.cnt, len(self.arr)) # Your MovingAverage object will be instantiated and called as such: # obj = MovingAverage(size) # param_1 = obj.next(val) ############ from collections import deque # with no sum variable, calculate on the fly class MovingAverage: def __init__(self, size: int): self.queue = deque() self.size = size self.avg = 0 def next(self, val: int) -> float: if len(self.queue) < self.size: self.queue.append(val) self.avg = sum(self.queue) / len(self.queue) return self.avg else: head = self.queue.popleft() self.queue.append(val) minus = head / self.size add = val / self.size self.avg = self.avg + add - minus return self.avg ############ from collections import deque class MovingAverage(object): def __init__(self, size): """ Initialize your data structure here. :type size: int """ self.windowSize = size self.windowSum = 0.0 self.data = deque([]) def next(self, val): """ :type val: int :rtype: float """ self.windowSum += val data = self.data leftTop = 0 if len(data) >= self.windowSize: leftTop = data.popleft() data.append(val) self.windowSum -= leftTop if len(data) < self.windowSize: return self.windowSum / len(data) return self.windowSum / self.windowSize # Your MovingAverage object will be instantiated and called as such: # obj = MovingAverage(size) # param_1 = obj.next(val)
-
type MovingAverage struct { arr []int cnt int s int } func Constructor(size int) MovingAverage { arr := make([]int, size) return MovingAverage{arr, 0, 0} } func (this *MovingAverage) Next(val int) float64 { idx := this.cnt % len(this.arr) this.s += val - this.arr[idx] this.arr[idx] = val this.cnt++ return float64(this.s) / float64(min(this.cnt, len(this.arr))) } /** * Your MovingAverage object will be instantiated and called as such: * obj := Constructor(size); * param_1 := obj.Next(val); */