346. Moving Average from Data Stream

346. Moving Average from Data Stream

Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window.

Example:

MovingAverage m = new MovingAverage(3);
m.next(1) = 1
m.next(10) = (1 + 10) / 2
m.next(3) = (1 + 10 + 3) / 3
m.next(5) = (10 + 3 + 5) / 3

State the problem (as you understand it): 

  • while window is not full, insert new integers and return sum / current window size. If it's full, you need to replace the oldest integer with the new integer and return sum / window size

Solve examples that are big enough and are normal cases (manually to figure out the general solution): 

  • The next calls with 1, 10, 3 mean that we can just insert new integers and return sum / current window size because the window is not full. The next(5) call in the example means that we need to remove the oldest integer 1, insert the new integer 5 and return curent sum  / window size.
    1. if the number of integers doesn't equal to the given window size, then insert the new integer
    2. if the number of integers equal to the given window size, then remove the oldest integer and insert the new integer.
    3. return sum of integers / current window size

Ask clarification questions:

State assumptions:

Consider several test cases (edge cases, base cases):

See if a Data Structure fits the problem:

  1. use a queue

See if an Algorithm fits the problem:

  1. ad-hoc algorithm

Extract the core problem:

  • implement a circular queue of the given size. 
    • a circular queue, circular buffer, or ring buffer is a variant of the linear queue that uses a single, fixed-size buffer where the last position if connected back to the first position to make a circule

Try breaking it down into subproblems:

Explain Potential Solutions (see solutin section):

Other solutions:

  1. use an array or list

Compare solutions:

  • using queue is easier because you can remove from front and add to back in O(1). If using array or list, you need to keep track of where the oldest element is (it moves every time).

Follow Up (TODO):

  1. change average to medium

Solution 1:


Ideas: 

  • keep track of the sum of the window as we go. This prevents an O(n) traversal over the queue as we add new number to get the new average. If we need to evict, then just subtract the first number off of our sum.

Steps:

  1. create instance variables
    1. create a queue of integers to represent the window
    2. create double sum to keep track of the current sum
    3. create int maxSize to keep track of the max size of the window
  2. implement the next() method:
    1. if current window size equal to maxSize, then remove the first integer from the queue and subtract it off of the current sum
    2. add the new val to current sum
    3. return sum / current window size

Validate the correctness (of your pseudocode with a test case):

Data Structure:

  • use a queue

Time Complexity:

  • O(1)

Space Complexity:

  • O(1)
class MovingAverage {
    
    private Queue<Integer> window = new ArrayDeque<>();
    private int maxSize;
    private double sum = 0.0;

    /** Initialize your data structure here. */
    public MovingAverage(int size) {
        this.maxSize = size;
    }
    
    public double next(int val) {
        if (this.window.size() == this.maxSize) {
            this.sum -= this.window.poll();
        }    
        
        this.sum += val;
        this.window.offer(val);
        return this.sum / this.window.size();
    }
}

Test your code again to make sure you don't have any bugs.

Solution 2:


Ideas: 

  • use an array to keep appending new numbers until it is full, then after it is full, new numbers will replace the oldest element in the array

Steps:

  1. create instance variables
    1. use a int array to represent the window of integers
    2. use int len to represent the number of integers in the window
    3. use int insert to represent the insert position for new integer
    4. use long sum to represent the sum of integers
  2. implement next() method
    1. if len is less than window size, then increment len
    2. subtract the integer at the insert positon from the sum and add the given val to the sum
    3. add val to the insert position
    4. update insert position by adding 1 to insert first and modding the window size
    5. return sum / len

Validate the correctness (of your pseudocode with a test case):

Data Structure:

  • use an array

Time Complexity:

  • O(1)

Space Complexity:

  • O(1)
class MovingAverage {
    
    private int[] window;
    private int len = 0;
    private int insertIndex = 0;
    private long sum = 0L;

    /** Initialize your data structure here. */
    public MovingAverage(int size) {
        this.window = new int[size];
    }
    
    public double next(int val) {
        if (this.len < this.window.length) {
            len++;
        }        
        sum -= window[insertIndex];
        sum += val;
        this.window[insertIndex] = val;
        
        this.insertIndex = (this.insertIndex + 1) % this.window.length;
        
        return (double) this.sum / this.len; 
    }
}

Test your code again to make sure you don't have any bugs.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值