Design your implementation of the circular double-ended queue (deque).
Implement the MyCircularDeque
class:
MyCircularDeque(int k)
Initializes the deque with a maximum size of k
.boolean insertFront()
Adds an item at the front of Deque. Returns true
if the operation is successful, or false
otherwise.boolean insertLast()
Adds an item at the rear of Deque. Returns true
if the operation is successful, or false
otherwise.boolean deleteFront()
Deletes an item from the front of Deque. Returns true
if the operation is successful, or false
otherwise.boolean deleteLast()
Deletes an item from the rear of Deque. Returns true
if the operation is successful, or false
otherwise.int getFront()
Returns the front item from the Deque. Returns -1
if the deque is empty.int getRear()
Returns the last item from Deque. Returns -1
if the deque is empty.boolean isEmpty()
Returns true
if the deque is empty, or false
otherwise.boolean isFull()
Returns true
if the deque is full, or false
otherwise.
Example 1:
Input ["MyCircularDeque", "insertLast", "insertLast", "insertFront", "insertFront", "getRear", "isFull", "deleteLast", "insertFront", "getFront"] [[3], [1], [2], [3], [4], [], [], [], [4], []] Output [null, true, true, true, false, 2, true, true, true, 4] Explanation MyCircularDeque myCircularDeque = new MyCircularDeque(3); myCircularDeque.insertLast(1); // return True myCircularDeque.insertLast(2); // return True myCircularDeque.insertFront(3); // return True myCircularDeque.insertFront(4); // return False, the queue is full. myCircularDeque.getRear(); // return 2 myCircularDeque.isFull(); // return True myCircularDeque.deleteLast(); // return True myCircularDeque.insertFront(4); // return True myCircularDeque.getFront(); // return 4
Constraints:
1 <= k <= 1000
0 <= value <= 1000
2000
calls will be made to insertFront
, insertLast
, deleteFront
, deleteLast
, getFront
, getRear
, isEmpty
, isFull
.This problem requires designing a circular deque data structure. A circular deque is a double-ended queue where the beginning and end are connected, allowing for efficient insertion and deletion at both ends. The solution utilizes an array to implement this structure.
The core idea is to use a fixed-size array to store the deque elements and track the front
and size
of the deque. The front
index points to the first element, and size
indicates the number of elements currently in the deque. Circular behavior is achieved using the modulo operator (%
) when calculating indices.
Key Data Structures:
q
: An array to store the deque elements.front
: An integer representing the index of the front element.size
: An integer representing the number of elements in the deque.capacity
: An integer representing the maximum capacity of the deque.Operations:
insertFront(value)
: Inserts an element at the front of the deque. If the deque is full, it returns false
. Otherwise, it adjusts the front
index, places the value, and increments size
.insertLast(value)
: Inserts an element at the rear of the deque. Similar logic as insertFront
, but it calculates the rear index using (front + size) % capacity
.deleteFront()
: Deletes the front element. If the deque is empty, it returns false
. Otherwise, it adjusts the front
index and decrements size
.deleteLast()
: Deletes the last element. Similar logic as deleteFront
, but it only decrements size
as the front
index doesn't change when deleting from the end.getFront()
: Returns the front element. If the deque is empty, it returns -1
.getRear()
: Returns the rear element. If the deque is empty, it returns -1
.isEmpty()
: Returns true
if the deque is empty (size == 0
), otherwise false
.isFull()
: Returns true
if the deque is full (size == capacity
), otherwise false
.Time Complexity:
insertFront
, insertLast
, deleteFront
, deleteLast
, getFront
, getRear
, isEmpty
, isFull
) have a time complexity of O(1). This is because they involve a constant number of operations regardless of the size of the deque.Space Complexity:
The Python code implements the above logic directly. The modulo operator (%
) ensures that the indices wrap around the circular buffer, simulating circular behavior. For example, self.front = (self.front - 1 + self.capacity) % self.capacity
correctly handles wrapping when the front pointer reaches the beginning of the array. Similar logic is used for insertLast
and getting the rear element.
The other methods are straightforward implementations of the operations described above, always checking for empty or full conditions before proceeding.
The provided solution efficiently implements a circular deque using a fixed-size array. The use of the modulo operator and careful tracking of front
and size
ensure that all operations maintain O(1) time complexity, making it suitable for applications requiring fast insertion and deletion at both ends of a queue-like structure.