Design a data structure to implement a queue-like data structure that follows the Most Recently Used (MRU) principle.
Implement the MRUQueue class:
MRUQueue(int n) initializes the queue with n elements: [1, 2, 3, ..., n].fetch(int k) moves the kth element to the end of the queue and returns it.Example 1:
Input:
["MRUQueue", "fetch", "fetch", "fetch", "fetch"]
[[8], [3], [5], [2], [8]]
Output:
[null, 3, 6, 2, 8]
Explanation:
MRUQueue mRUQueue = new MRUQueue(8); // Initializes the queue to [1, 2, 3, 4, 5, 6, 7, 8].
mRUQueue.fetch(3); // Moves the 3rd element (3) to the end of the queue to become [1, 2, 4, 5, 6, 7, 8, 3] and returns it.
mRUQueue.fetch(5); // Moves the 5th element (6) to the end of the queue to become [1, 2, 4, 5, 7, 8, 3, 6] and returns it.
mRUQueue.fetch(2); // Moves the 2nd element (2) to the end of the queue to become [1, 4, 5, 7, 8, 3, 6, 2] and returns it.
mRUQueue.fetch(8); // Moves the 8th element (2) to the end of the queue to become [1, 4, 5, 7, 8, 3, 6, 2] and returns it.
Constraints:
1 <= n <= 20001 <= k <= n2000 calls will be made to fetch.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We want to design a special kind of queue that always keeps track of the most recently used items. The brute force approach involves examining every single possible arrangement or sequence of operations to see how it affects the order of items.
Here's how the algorithm would work step-by-step:
class MostRecentlyUsedQueue:
def __init__(self):
self.tracked_items = []
def access_item(self, item_to_access):
# We must move the accessed item to the front, signifying it's the most recent.
if item_to_access in self.tracked_items:
self.tracked_items.remove(item_to_access)
self.tracked_items.insert(0, item_to_access)
def get_queue_order(self):
# Simulating access for every item to observe potential state changes.
original_order = list(self.tracked_items)
all_possible_next_states = []
# This loop represents examining each item as the 'next' accessed.
for _ in range(len(original_order)):
# To check each item, we simulate accessing it and record the resulting order.
current_item_to_simulate = original_order[_]
simulated_queue = MostRecentlyUsedQueue()
simulated_queue.tracked_items = list(original_order)
simulated_queue.access_item(current_item_to_simulate)
all_possible_next_states.append(simulated_queue.tracked_items)
# This final order is representative of the current state after all simulations.
return self.tracked_itemsThe goal is to keep track of items that are used most recently. Instead of searching through everything each time, we'll organize the items so the most recently used one is always easy to find and move to the front.
Here's how the algorithm would work step-by-step:
class MostRecentlyUsedQueue:
def __init__(self):
self.recent_items_list = []
def use_item(self, item_value):
# If the item is already in the queue, we need to move it to the front.
if item_value in self.recent_items_list:
self.recent_items_list.remove(item_value)
# New or existing items are always placed at the front to signify most recent use.
self.recent_items_list.insert(0, item_value)
def get_most_recently_used(self):
# The front of the list is maintained as the most recently used item.
if not self.recent_items_list:
return None
return self.recent_items_list[0]
def get_all_items_in_order(self):
# This method provides the current state of the queue from most to least recently used.
return self.recent_items_list| Case | How to Handle |
|---|---|
| Empty initial list for initialization | The data structure should initialize as empty and handle subsequent operations gracefully. |
| K value is out of bounds (less than 1 or greater than current size) | An exception or specific error value should be returned to indicate an invalid retrieval index. |
| Retrieving the very last element (most recently used) | This should be a valid operation and correctly move the last element to the end (which is itself). |
| Retrieving the first element (least recently used) | This should correctly move the first element to the end and update its recency. |
| Initial list contains duplicate elements | The data structure should treat each instance of a duplicate element as distinct for recency tracking. |
| Large number of elements and frequent retrievals | The chosen data structure (e.g., doubly linked list with a hash map) must provide efficient O(1) average time complexity for both operations to scale. |
| Initial list has only one element | Retrieving the 1st most recently used element should return that element and keep it at the end. |
| All elements in the initial list are identical | The structure should correctly manage the recency of each identical element, moving the retrieved one to the end. |