Design Front Middle Back Queue - Complete Solution Guide
Design Front Middle Back Queue is LeetCode problem 1670, a Medium level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
Design a queue that supports push and pop operations in the front, middle, and back. Implement the FrontMiddleBack class: FrontMiddleBack() Initializes the queue. void pushFront(int val) Adds val to the front of the queue. void pushMiddle(int val) Adds val to the middle of the queue. void pushBack(int val) Adds val to the back of the queue. int popFront() Removes the front element of the queue and returns it. If the queue is empty, return -1 . int popMiddle() Removes the middle element of the qu
Detailed Explanation
The problem requires designing a queue-like data structure that supports push and pop operations from the front, middle, and back. The `FrontMiddleBackQueue` class must implement the following methods: * `pushFront(int val)`: Adds `val` to the front of the queue. * `pushMiddle(int val)`: Adds `val` to the middle of the queue. If the queue has an odd number of elements, the new element is inserted at the index (n-1)/2. If the queue has an even number of elements, the new element is inserted at index n/2. The example given clarifies the middle is always inserted towards the front when there are two possible middle indices. * `pushBack(int val)`: Adds `val` to the back of the queue. * `popFront()`: Removes and returns the element at the front of the queue. Returns -1 if the queue is empty. * `popMiddle()`: Removes and returns the element at the middle of the queue. Returns -1 if the queue is empty. If there are two middle elements (even size queue), remove the leftmost middle element (index n/2 - 1). * `popBack()`: Removes and returns the element at the back of the queue. Returns -1 if the queue is empty. The problem emphasizes the importance of handling the 'middle' element correctly when the queue size is even.
Solution Approach
The solution utilizes two deques: `left` and `right`. The `left` deque stores the left half of the queue, including the middle element when the queue size is odd. The `right` deque stores the right half of the queue. A `rebalance` function is used after each push/pop operation to ensure the deques are properly balanced. This approach allows efficient O(1) operations for pushing and popping from front, middle and back.
Step-by-Step Algorithm
- Step 1: Initialize two deques, `left` and `right`, in the constructor.
- Step 2: Implement `pushFront(val)`: Add `val` to the front of the `left` deque and call the `rebalance()` function.
- Step 3: Implement `pushMiddle(val)`: If `len(left) > len(right)`, move the last element of `left` to the front of `right`. Then add `val` to the back of `left`.
- Step 4: Implement `pushBack(val)`: Add `val` to the back of the `right` deque and call the `rebalance()` function.
- Step 5: Implement `popFront()`: If `left` is empty, return -1. Otherwise, remove and return the front element of `left` and call the `rebalance()` function.
- Step 6: Implement `popMiddle()`: If `left` is empty, return -1. Otherwise, remove and return the last element of `left` and call the `rebalance()` function.
- Step 7: Implement `popBack()`: If `left` is empty, return -1. Otherwise, if `right` is not empty, remove and return the last element of `right`. If `right` is empty, remove and return the last element of `left`. Then call the `rebalance()` function.
- Step 8: Implement `rebalance()`: If `len(left) > len(right) + 1`, move the last element of `left` to the front of `right`. If `len(left) < len(right)`, move the front element of `right` to the back of `left`.
Key Insights
- Insight 1: The key is to efficiently handle insertions and deletions from the front, middle, and back. Using a single data structure like an array or linked list would make operations like pushMiddle or popMiddle potentially O(n) because you need to shift elements.
- Insight 2: Using two deques (double-ended queues) can efficiently solve this problem. One deque (`left`) stores the left half of the queue and the other (`right`) stores the right half. This allows for O(1) insertions and deletions from both ends.
- Insight 3: Maintaining balance between the two deques is crucial to ensure that the middle element can be accessed in O(1) time. The rebalancing operation ensures that `abs(len(left) - len(right))` is at most 1 at all times.
Complexity Analysis
Time Complexity: O(1)
Space Complexity: O(n)
Topics
This problem involves: Array, Linked List, Design, Queue, Data Stream.
Companies
Asked at: Citadel.