Opening the reading…
Opening the reading…
QUEUE › IMPLEMENTATION PROBLEMS
Open — the attempt gate is not wired up yet
This editorial is meant to unlock after you have run the problem at least once, with the worked solution behind one further deliberate click. That needs per-learner unlock state nothing stores today, so for now the whole article is open.
Try it yourself first →A queue removes the oldest item and adds new items after the newest one. In a normal array, repeatedly removing from the front would leave unused cells at the beginning, and shifting the remaining values would make deletion expensive. A circular queue avoids both problems by treating the last array cell as adjacent to the first, so a pointer can wrap around and reuse released cells.
Use front for the index of the current first item and rear for the next position where an item will be inserted. The number of stored items is kept separately in size. That count is the important third piece of state: without it, front equal to rear could mean either an empty queue or a full queue.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(1) per operation | Each queue method performs only a fullness or emptiness check, at most one array access, one index update, and one size update. No operation shifts or scans existing items. |
| Space | O(k) extra | The allocated array has exactly k cells, and the queue stores only four scalar fields besides it. The returned output vector is required output and is excluded from the extra-space bound; the bound is O(k) in every input shape. |
#include <string>
#include <vector>
using namespace std;
class MyCircularQueue {
int* arr;
int front;
int rear;
int size;
int capacity;
public:
MyCircularQueue(int k) : arr(new int[k]), front(0), rear(0), size(0), capacity(k) {}
~MyCircularQueue() {
delete[] arr;
}
bool enQueue(int value) {
if (isFull()) return false;
arr[rear] = value;
rear = (rear + 1) % capacity;
size++;
return true;
}
bool deQueue() {
if (isEmpty()) return false;
front = (front + 1) % capacity;
size--;
return true;
}
int Front() {
if (isEmpty()) return -1;
return arr[front];
}
int Rear() {
if (isEmpty()) return -1;
return arr[(rear - 1 + capacity) % capacity];
}
bool isEmpty() {
return size == 0;
}
bool isFull() {
return size == capacity;
}
};
class Solution {
public:
vector<string> execute(vector<string> ops, vector<vector<int>> vals) {
vector<string> result;
MyCircularQueue* queue = nullptr;
for (int i = 0; i < static_cast<int>(ops.size()); i++) {
if (ops[i] == "MyCircularQueue") {
queue = new MyCircularQueue(vals[i][0]);
result.push_back("null");
} else if (ops[i] == "enQueue") {
result.push_back(queue->enQueue(vals[i][0]) ? "true" : "false");
} else if (ops[i] == "deQueue") {
result.push_back(queue->deQueue() ? "true" : "false");
} else if (ops[i] == "Front") {
result.push_back(to_string(queue->Front()));
} else if (ops[i] == "Rear") {
result.push_back(to_string(queue->Rear()));
} else if (ops[i] == "isEmpty") {
result.push_back(queue->isEmpty() ? "true" : "false");
} else if (ops[i] == "isFull") {
result.push_back(queue->isFull() ? "true" : "false");
}
}
delete queue;
return result;
}
};The key placement choice is that rear always means the next insertion position. This makes enQueue direct, but it means Rear must look one position backward. Adding capacity before taking the modulo keeps that backward step non-negative when rear is 0. The destructor releases the manually allocated array after execute finishes, so the queue does not leave its storage behind.