Design O(1) cache and moving average
AtlassianMachine Learning Engineer · OnsiteLast updated
This problem tests your ability to maintain constant-time complexity for both cache management and sliding-window statistics by using a combination of a doubly-linked list and hash maps.
Problem Statement
You are tasked with building a StreamProcessor class that performs two distinct operations on a stream of integer values:
- LRU Cache: Store up to
capacitykey-value pairs. If the cache reaches capacity, evict the least recently used item. Theput(key, value)andget(key)methods must both execute inO(1)time. - Moving Average: Maintain a sliding window of the last
kvalues added to the system. Provide agetMovingAverage()method that returns the current average of thesekvalues inO(1)time.
Implementation Signature
class StreamProcessor:
def __init__(self, capacity: int, k: int):
# Initialize cache with capacity and moving average window size k
pass
def put(self, key: int, value: int) -> None:
# Update/insert the key-value pair and include value in the moving average
pass
def get(self, key: int) -> int:
# Return the value for the key, or -1 if not found
pass
def getMovingAverage(self) -> float:
# Return the average of the last k values added (global stream)
pass
Constraints
capacityandkare positive integers.putis called frequently;getandgetMovingAveragemust be highly performant.- The moving average should include all values passed to
put, even if the key is already in the cache.
Examples
Example 1
Input: processor = StreamProcessor(2, 3)
put(1, 10)-> Average window: [10], Avg: 10.0put(2, 20)-> Average window: [10, 20], Avg: 15.0put(3, 30)-> Average window: [10, 20, 30], Avg: 20.0put(4, 40)-> Average window: [20, 30, 40], Avg: 30.0 (Key 1 evicted)
Edge Cases
- Accessing a key that does not exist.
- Calling
getMovingAveragebeforekelements have been added. - Consecutive
putcalls with the same key.
Hints
Hint 1
Use a Doubly Linked List combined with a Hash Map to achieve O(1) performance for the LRU cache.
Hint 2
For the moving average, maintain a running sum of the last k elements and a circular buffer (or a queue) to track which elements to subtract when the window slides.
Hint 3
Ensure that the cache eviction logic and the moving average logic remain decoupled, as the moving average tracks the stream of values, not the set of keys currently in the cache.
Follow-up questions
- How would your moving average implementation change if the window size k was extremely large, potentially causing overflow in the running sum?
- If this system needs to be thread-safe, what synchronization primitives would you use, and how would they impact throughput?
- How would you modify the system to provide a weighted moving average where more recent values have a higher impact?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.