This problem requires designing a data structure that simulates a queue but prioritizes the most recently used element. The most straightforward approach uses a list (or array) and manipulates it directly, but this leads to O(n) time complexity for each fetch
operation. A more efficient solution utilizes a Binary Indexed Tree (BIT) to achieve a logarithmic time complexity for fetch
.
Approach 1: List Manipulation (O(n) for fetch)
This approach is simpler to implement. It directly maintains the queue as a list. When fetch(k)
is called, the k-th element is removed from its position and appended to the end.
class MRUQueue:
def __init__(self, n: int):
self.q = list(range(1, n + 1))
def fetch(self, k: int) -> int:
ans = self.q[k - 1]
self.q.pop(k - 1) # Remove from original position
self.q.append(ans) # Add to the end
return ans
fetch
. Removing an element from the middle of a list takes O(n) time in the worst case.Approach 2: Binary Indexed Tree (BIT) for Optimized Fetch (O(log n) for fetch)
This approach uses a BIT to efficiently track the positions of elements in the queue. The BIT allows us to find the actual index of the k-th element in O(log n) time.
Data Structures:
q
: A list (or array) storing the elements of the queue.tree
: A Binary Indexed Tree to maintain the cumulative count of elements. This helps to find the actual index of the kth element in the queue quickly.Algorithm:
__init__(n)
: Initialize the queue q
with elements from 1 to n and the BIT tree
.fetch(k)
:
q
using the BIT tree
to find the index idx
of the k-th element. The BIT helps determine which index corresponds to the k-th element after the elements might be reordered.q[idx]
and append it to the end of q
.tree
to reflect the change in the queue.Code (Python):
class BinaryIndexedTree:
# ... (Binary Indexed Tree implementation as shown before) ...
class MRUQueue:
def __init__(self, n: int):
self.q = list(range(1, n + 1))
self.tree = BinaryIndexedTree(n + 2010) # +2010 for safety margin
def fetch(self, k: int) -> int:
l, r = 1, len(self.q)
while l < r:
mid = (l + r) // 2
if mid - self.tree.query(mid) >= k:
r = mid
else:
l = mid + 1
x = self.q[l-1] # Adjust index since we're using 1-based indexing
self.q.pop(l - 1)
self.q.append(x)
return x
fetch
. Binary search takes O(log n) time, and BIT updates also take O(log n) time.Comparison:
| Feature | Approach 1 (List) | Approach 2 (BIT) |
|----------------|--------------------|--------------------|
| fetch
Time | O(n) | O(log n) |
| Space | O(n) | O(n) |
| Implementation | Simpler | More complex |
The Binary Indexed Tree approach provides a significant performance improvement for frequent fetch
operations, making it more suitable for larger values of n
and numerous calls to fetch
. The provided code in different languages showcases the BIT-based solution, though the list-based solution would be a simpler, yet less efficient, alternative.