← DSA Atlas
Dedicated problem page · #622

Design Circular Queue

MediumData Structure DesignRing buffer with head + sizeFixed array with modular indexing
Solve on LeetCode ↗
622
MediumData Structure DesignFixed array with modular indexingRing buffer with head + size

Design Circular Queue

Design a circular queue of fixed capacity k. enQueue(value) inserts at the rear and returns true, or false if the queue is full. deQueue() removes the front element and returns true, or false if empty. Front() and Rear() return the front and rear values or -1 if empty. isEmpty() and isFull() report the state. The circular design reuses freed slots at the front instead of wasting space.

Open official problem prompt ↗
In plain English

Implement a fixed-capacity FIFO queue that reuses freed front slots, with every operation in constant time.

Picture it like this

Like a circular parking lot with numbered spots: cars leave from the front and new cars fill the next open spot, and the counting wraps back to spot 0 after the last one.

Example
Input
MyCircularQueue(3); enQueue(1); enQueue(2); enQueue(3); enQueue(4); Rear(); isFull(); deQueue(); enQueue(4); Rear()
Output
[null, true, true, true, false, 3, true, true, true, 4]
Why
The 4th enQueue fails (full, capacity 3); after one deQueue frees a slot, enQueue(4) succeeds and Rear() is 4.
Constraints
1 <= k <= 10000 <= value <= 1000At most 3000 calls across all methodsAll operations must run in O(1) time
Pattern lesson

See the pattern, then code

Ring buffer with head + size
Recognition clue

A fixed-size FIFO that must recycle space when the front is removed - the classic ring buffer with wraparound indexing.

Data Structure Design

An API whose operations must meet strict O(1) or O(log n) contracts.. Store a head index and a live count; the rear slot is (head + count) mod k, so you never shift elements - indices simply wrap around the fixed array.

New words, made simpleKnow these before the algorithm
Ring buffer
A fixed array treated as circular via modular arithmetic.
Head index
Position of the current front element.
Wraparound
Using % k so an index past the end returns to the start.
Approaches from first idea to best ideaCompare the trade-offs
ApproachHow it thinksCost
Python list with pop(0)

Front removal shifts all elements - not O(1) and not fixed-capacity.

Use a dynamic list and pop from the front on dequeue.

Time O(n) per dequeueSpace O(n)
The rule we keep true

Invariant

count always equals the number of live elements, and they occupy slots head, head+1, ..., head+count-1 taken modulo k.

Why this is correct

Reasoning

Storing count (rather than only head and tail pointers) removes the classic full-vs-empty ambiguity: full is count == k and empty is count == 0, and modular indexing guarantees the used slots stay contiguous around the ring without ever moving data.

The algorithm in three movesSay these aloud before coding
1Allocate an array of size k and track head index and current count

head=0, count=3, q=[1,2,3]

2enQueue writes to (head + count) % k and increments count if not full

enQueue(4): count==cap -> False

3deQueue advances head to (head + 1) % k and decrements count if not empty

deQueue: head=1; enQueue(4): q[(1+2)%3=0]=4

4Front is q[head]; Rear is q[(head + count - 1) % k]; empty/full compare count to 0 and k

Visual trace

Follow the data, one decision at a time

Input snapshotHighlighted cells are involved in this example
_0
_1
_2
1 · Readthree inserts
2 · Askfull?
3 · Update stateq=[1,2,3], head=0, count=3
4 · Resultall true
Key takeaway

A size-3 ring buffer where the rear index wraps to slot 0 after a dequeue frees it.

Code walkthrough

Read the solution in small chunks

Python 3

Do not memorize the whole program. Connect each group of lines to one job in the algorithm.

  1. 1
    Lines 2-6State

    A pre-sized array, capacity, head index, and live count.

  2. 2
    Lines 8-13enQueue

    Reject when full; otherwise write at (head + count) % cap and grow count.

  3. 3
    Lines 15-20deQueue

    Reject when empty; otherwise advance head modulo cap and shrink count.

  4. 4
    Lines 22-30Front / Rear

    Front is q[head]; rear is computed with the same modular offset, both -1 when empty.

  5. 5
    Lines 32-36isEmpty / isFull

    Direct comparisons of count against 0 and capacity.

Make it stick

Edge cases, mistakes, and one self-check

E

Edge cases to test

  • Capacity 1 queue toggles between empty and full on each op
  • deQueue on empty returns false without touching head
  • Rear right after wraparound reads slot 0 correctly
  • Front and Rear on an empty queue both return -1
!

Common beginner mistakes

  • Confusing full and empty when using only head/tail pointers without a count
  • Computing rear as head + count instead of head + count - 1 (off by one)
  • Forgetting the modulo on the rear/enqueue index so it runs off the array
  • Using list.pop(0), which is O(n) and abandons the fixed-capacity design
Check your understanding

Why does storing a count avoid the full-versus-empty ambiguity that plagues head/tail-only ring buffers?