Problem Statement (Asked By Twitter)
You manage an e-commerce website and need to keep track of the last N order IDs in a log. Design a data structure that supports the following operations efficiently:
record(order_id) – Adds the given order_id to the log.get_last(i) – Retrieves the i-th most recent order ID from the log. It is guaranteed that i ≤ N.Your implementation should optimize both time and space usage.
Problem link: https://leetcode.com/problems/reorder-data-in-log-files/description/
Disclaimer: Try solving the problem on your own first! Use this solution only as a reference to learn and improve.
An array is an ideal data structure for this problem since it allows constant-time indexing.
We can initialize an array of size N and maintain a log of recent orders. When recording new orders:
This ensures that both recording and retrieving orders take O(1) time.
record()):
import java.util.ArrayList;
import java.util.List;
class Log {
private final int capacity;
private final List<Integer> log;
public Log(int n) {
this.capacity = n;
this.log = new ArrayList<>();
}
public void record(int orderId) {
if (log.size() >= capacity) {
log.remove(0); // Remove the oldest order (slow operation)
}
log.add(orderId);
}
public int getLast(int i) {
return log.get(log.size() - i);
}
public static void main(String[] args) {
Log orderLog = new Log(5);
orderLog.record(101);
orderLog.record(102);
orderLog.record(103);
orderLog.record(104);
orderLog.record(105);
orderLog.record(106); // Oldest (101) is removed
System.out.println(orderLog.getLast(1)); // Output: 106
System.out.println(orderLog.getLast(3)); // Output: 104
}
}
This approach works but record() takes O(N) time due to shifting elements in ArrayList.remove(0).
record()):
class CircularLog {
private final int[] log;
private final int capacity;
private int curIndex;
public CircularLog(int n) {
this.capacity = n;
this.log = new int[n];
this.curIndex = 0;
}
public void record(int orderId) {
log[curIndex] = orderId; // Overwrite the oldest order
curIndex = (curIndex + 1) % capacity; // Move index in circular fashion
}
public int getLast(int i) {
int index = (curIndex - i + capacity) % capacity; // Handle negative indices
return log[index];
}
public static void main(String[] args) {
CircularLog orderLog = new CircularLog(5);
orderLog.record(101);
orderLog.record(102);
orderLog.record(103);
orderLog.record(104);
orderLog.record(105);
orderLog.record(106); // Overwrites 101
System.out.println(orderLog.getLast(1)); // Output: 106
System.out.println(orderLog.getLast(3)); // Output: 104
}
}
curIndex, overwriting old values instead of shifting elements.curIndex = (curIndex + 1) % capacity ensures that we wrap around when reaching the array’s end.index=(curIndex−i+capacity) mod capacity
This prevents negative indices whencurIndex < i.
| Operation | Naïve Approach | Circular Buffer |
|---|---|---|
record() | O(N) (due to shifting) | O(1) (direct overwrite) |
getLast(i) | O(1) | O(1) |
Circular Buffer is much more efficient for large N, ensuring constant-time performance.
Did this solution help you understand the concept better? Let me know your thoughts in the comments below! Don’t forget to follow us on Instagram @coderz.py for more DSA tips and solutions to ace your coding interviews.
A design pattern is a reusable solution to a commonly occurring problem in software design. They…
Factory Method is a creational design pattern that deals with the object creation. It separates…
You are given two singly linked lists that intersect at some node. Your task is…
A builder plans to construct N houses in a row, where each house can be…
Find the length of the longest absolute path to a file within the abstracted file…
You are given a stream of elements that is too large to fit into memory.…