|
| 1 | +# https://leetcode.com/problems/design-most-recently-used-queue/description/ |
| 2 | + |
| 3 | +''' |
| 4 | +Design a queue-like data structure that moves the most recently used element to the end of the queue. |
| 5 | +
|
| 6 | +Implement the MRUQueue class: |
| 7 | +
|
| 8 | +MRUQueue(int n) constructs the MRUQueue with n elements: [1,2,3,...,n]. |
| 9 | +int fetch(int k) moves the kth element (1-indexed) to the end of the queue and returns it. |
| 10 | + |
| 11 | +
|
| 12 | +Example 1: |
| 13 | +
|
| 14 | +Input: |
| 15 | +["MRUQueue", "fetch", "fetch", "fetch", "fetch"] |
| 16 | +[[8], [3], [5], [2], [8]] |
| 17 | +Output: |
| 18 | +[null, 3, 6, 2, 2] |
| 19 | +
|
| 20 | +Explanation: |
| 21 | +MRUQueue mRUQueue = new MRUQueue(8); // Initializes the queue to [1,2,3,4,5,6,7,8]. |
| 22 | +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. |
| 23 | +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. |
| 24 | +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. |
| 25 | +mRUQueue.fetch(8); // The 8th element (2) is already at the end of the queue so just return it. |
| 26 | + |
| 27 | +
|
| 28 | +Constraints: |
| 29 | +
|
| 30 | +1 <= n <= 2000 |
| 31 | +1 <= k <= n |
| 32 | +At most 2000 calls will be made to fetch. |
| 33 | +
|
| 34 | +Follow up: Finding an O(n) algorithm per fetch is a bit easy. Can you find an algorithm with a better complexity for each fetch call? |
| 35 | +''' |
| 36 | + |
| 37 | +class Fenwick: |
| 38 | + def __init__(self,n): |
| 39 | + self.n=n |
| 40 | + self.bit=[0]*(n+1) |
| 41 | + |
| 42 | + def add(self,i,delta): |
| 43 | + while i<=self.n: |
| 44 | + self.bit[i]+=delta |
| 45 | + i+=i&-i |
| 46 | + |
| 47 | + def sum(self,i): |
| 48 | + res=0 |
| 49 | + while i>0: |
| 50 | + res+=self.bit[i] |
| 51 | + i-=i&-i |
| 52 | + return res |
| 53 | + |
| 54 | + def kth(self,k): |
| 55 | + idx=0 |
| 56 | + bit_mask=1<<(self.n.bit_length()) |
| 57 | + while bit_mask: |
| 58 | + nxt=idx+bit_mask |
| 59 | + if nxt<=self.n and self.bit[nxt]<k: |
| 60 | + idx=nxt |
| 61 | + k-=self.bit[nxt] |
| 62 | + bit_mask>>=1 |
| 63 | + return idx+1 |
| 64 | + |
| 65 | + def kth(self,k): |
| 66 | + idx=0 |
| 67 | + bit_mask=1<<(self.n.bit_length()) |
| 68 | + while bit_mask: |
| 69 | + nxt=idx+bit_mask |
| 70 | + if nxt<=self.n and self.bit[nxt]<k: |
| 71 | + idx=nxt |
| 72 | + k-=self.bit[nxt] |
| 73 | + bit_mask>>=1 |
| 74 | + return idx+1 |
| 75 | + |
| 76 | +class MRUQueue: |
| 77 | + |
| 78 | + def __init__(self, n: int): |
| 79 | + self.size=n |
| 80 | + self.vals=[0]*(n+2001) |
| 81 | + self.tree=Fenwick(n+2000) |
| 82 | + |
| 83 | + for i in range(1,n+1): |
| 84 | + self.vals[i]=i |
| 85 | + self.tree.add(i,1) |
| 86 | + |
| 87 | + def fetch(self, k: int) -> int: |
| 88 | + idx=self.tree.kth(k) |
| 89 | + val=self.vals[idx] |
| 90 | + |
| 91 | + self.tree.add(idx,-1) |
| 92 | + self.size+=1 |
| 93 | + self.vals[self.size]=val |
| 94 | + self.tree.add(self.size,1) |
| 95 | + return val |
| 96 | + |
| 97 | + |
| 98 | +# Your MRUQueue object will be instantiated and called as such: |
| 99 | +# obj = MRUQueue(n) |
| 100 | +# param_1 = obj.fetch(k) |
| 101 | + |
| 102 | +''' |
| 103 | +Complexity Analysis |
| 104 | +Let n be the size of the queue. |
| 105 | +
|
| 106 | +Time Complexity: O(log^2n) |
| 107 | +
|
| 108 | +The time complexity of the MRUQueue operations is determined by the use of a Fenwick Tree (Binary Indexed Tree) and binary search. |
| 109 | +The Fenwick Tree enables efficient prefix sum calculations and updates, while binary search is used to locate the k-th element in the queue. |
| 110 | +Initialization (MRUQueue(int n)): During initialization, the Fenwick Tree and the values array are set up. |
| 111 | +Each of the n elements is inserted into the Fenwick Tree using the insert operation, which takes O(logn) time per insertion. |
| 112 | +Since there are n elements, the total time complexity for initialization is O(nlogn). |
| 113 | +
|
| 114 | +Space Complexity: O(n+f) |
| 115 | +''' |
0 commit comments