Welcome to Subscribe On Youtube

1756. Design Most Recently Used Queue

Description

Design a queue-like data structure that moves the most recently used element to the end of the queue.

Implement the MRUQueue class:

  • MRUQueue(int n) constructs the MRUQueue with n elements: [1,2,3,...,n].
  • int fetch(int k) moves the kth element (1-indexed) 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, 2]

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); // The 8th element (2) is already at the end of the queue so just return it.

 

Constraints:

  • 1 <= n <= 2000
  • 1 <= k <= n
  • At most 2000 calls will be made to fetch.

 

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?

Solutions

  • class BinaryIndexedTree {
        private int n;
        private int[] c;
    
        public BinaryIndexedTree(int n) {
            this.n = n;
            this.c = new int[n + 1];
        }
    
        public void update(int x, int v) {
            while (x <= n) {
                c[x] += v;
                x += x & -x;
            }
        }
    
        public int query(int x) {
            int s = 0;
            while (x > 0) {
                s += c[x];
                x -= x & -x;
            }
            return s;
        }
    }
    
    class MRUQueue {
        private int n;
        private int[] q;
        private BinaryIndexedTree tree;
    
        public MRUQueue(int n) {
            this.n = n;
            q = new int[n + 2010];
            for (int i = 1; i <= n; ++i) {
                q[i] = i;
            }
            tree = new BinaryIndexedTree(n + 2010);
        }
    
        public int fetch(int k) {
            int l = 1, r = n;
            while (l < r) {
                int mid = (l + r) >> 1;
                if (mid - tree.query(mid) >= k) {
                    r = mid;
                } else {
                    l = mid + 1;
                }
            }
            int x = q[l];
            q[++n] = x;
            tree.update(l, 1);
            return x;
        }
    }
    
    /**
     * Your MRUQueue object will be instantiated and called as such:
     * MRUQueue obj = new MRUQueue(n);
     * int param_1 = obj.fetch(k);
     */
    
  • class BinaryIndexedTree {
    public:
        BinaryIndexedTree(int _n)
            : n(_n)
            , c(_n + 1) {}
    
        void update(int x, int delta) {
            while (x <= n) {
                c[x] += delta;
                x += x & -x;
            }
        }
    
        int query(int x) {
            int s = 0;
            while (x) {
                s += c[x];
                x -= x & -x;
            }
            return s;
        }
    
    private:
        int n;
        vector<int> c;
    };
    
    class MRUQueue {
    public:
        MRUQueue(int n) {
            q.resize(n + 1);
            iota(q.begin() + 1, q.end(), 1);
            tree = new BinaryIndexedTree(n + 2010);
        }
    
        int fetch(int k) {
            int l = 1, r = q.size();
            while (l < r) {
                int mid = (l + r) >> 1;
                if (mid - tree->query(mid) >= k) {
                    r = mid;
                } else {
                    l = mid + 1;
                }
            }
            int x = q[l];
            q.push_back(x);
            tree->update(l, 1);
            return x;
        }
    
    private:
        vector<int> q;
        BinaryIndexedTree* tree;
    };
    
    /**
     * Your MRUQueue object will be instantiated and called as such:
     * MRUQueue* obj = new MRUQueue(n);
     * int param_1 = obj->fetch(k);
     */
    
  • 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[k - 1 : k] = []
            self.q.append(ans)
            return ans
    
    
    # Your MRUQueue object will be instantiated and called as such:
    # obj = MRUQueue(n)
    # param_1 = obj.fetch(k)
    
    
  • type BinaryIndexedTree struct {
    	n int
    	c []int
    }
    
    func newBinaryIndexedTree(n int) *BinaryIndexedTree {
    	c := make([]int, n+1)
    	return &BinaryIndexedTree{n, c}
    }
    
    func (this *BinaryIndexedTree) update(x, delta int) {
    	for x <= this.n {
    		this.c[x] += delta
    		x += x & -x
    	}
    }
    
    func (this *BinaryIndexedTree) query(x int) int {
    	s := 0
    	for x > 0 {
    		s += this.c[x]
    		x -= x & -x
    	}
    	return s
    }
    
    type MRUQueue struct {
    	q    []int
    	tree *BinaryIndexedTree
    }
    
    func Constructor(n int) MRUQueue {
    	q := make([]int, n+1)
    	for i := 1; i <= n; i++ {
    		q[i] = i
    	}
    	return MRUQueue{q, newBinaryIndexedTree(n + 2010)}
    }
    
    func (this *MRUQueue) Fetch(k int) int {
    	l, r := 1, len(this.q)
    	for l < r {
    		mid := (l + r) >> 1
    		if mid-this.tree.query(mid) >= k {
    			r = mid
    		} else {
    			l = mid + 1
    		}
    	}
    	x := this.q[l]
    	this.q = append(this.q, x)
    	this.tree.update(l, 1)
    	return x
    }
    
    /**
     * Your MRUQueue object will be instantiated and called as such:
     * obj := Constructor(n);
     * param_1 := obj.Fetch(k);
     */
    
  • class BinaryIndexedTree {
        private n: number;
        private c: number[];
    
        constructor(n: number) {
            this.n = n;
            this.c = new Array(n + 1).fill(0);
        }
    
        public update(x: number, v: number): void {
            while (x <= this.n) {
                this.c[x] += v;
                x += x & -x;
            }
        }
    
        public query(x: number): number {
            let s = 0;
            while (x > 0) {
                s += this.c[x];
                x -= x & -x;
            }
            return s;
        }
    }
    
    class MRUQueue {
        private q: number[];
        private tree: BinaryIndexedTree;
    
        constructor(n: number) {
            this.q = new Array(n + 1);
            for (let i = 1; i <= n; ++i) {
                this.q[i] = i;
            }
            this.tree = new BinaryIndexedTree(n + 2010);
        }
    
        fetch(k: number): number {
            let l = 1;
            let r = this.q.length;
            while (l < r) {
                const mid = (l + r) >> 1;
                if (mid - this.tree.query(mid) >= k) {
                    r = mid;
                } else {
                    l = mid + 1;
                }
            }
            const x = this.q[l];
            this.q.push(x);
            this.tree.update(l, 1);
            return x;
        }
    }
    
    /**
     * Your MRUQueue object will be instantiated and called as such:
     * var obj = new MRUQueue(n)
     * var param_1 = obj.fetch(k)
     */
    
    

All Problems

All Solutions