622. Design Circular Queue - Detailed Explanation

Free Coding Questions Catalog
Boost your coding skills with our essential coding questions catalog. Take a step towards a better tech career now!

Problem Statement

Description:
You are required to design a circular queue with a fixed size. The circular queue supports the following operations:

  • MyCircularQueue(k):
    Initializes the circular queue with a maximum capacity of k.

  • enQueue(value):
    Inserts an element into the circular queue. Returns true if the operation is successful; otherwise, returns false.

  • deQueue():
    Deletes an element from the circular queue. Returns true if the operation is successful; otherwise, returns false.

  • Front():
    Gets the front item from the queue. If the queue is empty, return -1.

  • Rear():
    Gets the last item from the queue. If the queue is empty, return -1.

  • isEmpty():
    Checks whether the circular queue is empty.

  • isFull():
    Checks whether the circular queue is full.

Example 1:

  • Input:
    MyCircularQueue circularQueue = new MyCircularQueue(3); // set the size to be 3
    circularQueue.enQueue(1);  // return true
    circularQueue.enQueue(2);  // return true
    circularQueue.enQueue(3);  // return true
    circularQueue.enQueue(4);  // return false, the queue is full
    circularQueue.Rear();      // return 3
    circularQueue.isFull();    // return true
    circularQueue.deQueue();   // return true
    circularQueue.enQueue(4);  // return true
    circularQueue.Rear();      // return 4
    
  • Output:
    The operations should behave as described above.

Constraints:

  • 1 ≤ k ≤ 1000 (or similar bounds)
  • All values inserted will be integers.
  • The operations must work in O(1) time on average.

Hints

  • Hint 1:
    Think of the queue as a fixed-size array. Use two pointers (or indices) to track the front and rear positions.

  • Hint 2:
    To support wrap-around, use modulo arithmetic when incrementing your pointers. This will help you simulate a circular structure within a linear array.

  • Hint 3:
    Be careful when checking if the queue is empty or full. One common trick is to maintain a count of the current number of elements or reserve one slot in the array to distinguish between full and empty cases.

Approach 1: Using an Array with Head, Tail, and Count

Idea

  • Data Structure:
    Use a fixed-size array to store the elements. Maintain three variables:

    • head: The index of the front element.
    • tail: The index where the next element will be inserted.
    • count: The current number of elements in the queue.
  • Operations:

    • enQueue(value):
      If the queue is full (count == capacity), return false. Otherwise, insert the value at the tail index, then increment tail (using modulo arithmetic to wrap around) and increase the count.

    • deQueue():
      If the queue is empty (count == 0), return false. Otherwise, remove the element at the head, then increment head (using modulo arithmetic) and decrease the count.

    • Front():
      Return the element at head if not empty; otherwise, return -1.

    • Rear():
      The last element is at index (tail - 1 + capacity) % capacity if the queue is not empty.

    • isEmpty() / isFull():
      Use the count variable to check if the queue is empty or full.

Walkthrough Example

Let’s simulate operations on a circular queue of capacity 3:

  1. Initialize:

    • head = 0, tail = 0, count = 0, and an array of size 3.
  2. enQueue(1):

    • Insert 1 at tail index 0.
    • Set tail = (0 + 1) % 3 = 1 and count = 1.
  3. enQueue(2):

    • Insert 2 at tail index 1.
    • Set tail = (1 + 1) % 3 = 2 and count = 2.
  4. enQueue(3):

    • Insert 3 at tail index 2.
    • Set tail = (2 + 1) % 3 = 0 (wrap-around) and count = 3.
  5. enQueue(4):

    • The queue is full (count == capacity), so return false.
  6. Rear():

    • Calculate rear index as (tail - 1 + capacity) % capacity = (0 - 1 + 3) % 3 = 2.
    • Return element at index 2, which is 3.
  7. deQueue():

    • Remove the element at head index 0.
    • Set head = (0 + 1) % 3 = 1 and count = 2.
  8. enQueue(4):

    • Insert 4 at tail index 0.
    • Set tail = (0 + 1) % 3 = 1 and count = 3.
  9. Rear():

    • Now the rear index is (tail - 1 + capacity) % capacity = (1 - 1 + 3) % 3 = 3 % 3 = 0.
    • Return element at index 0, which is 4.

Code Implementation

Python Code

Python3
Python3

. . . .

Java Code

Java
Java

. . . .

Complexity Analysis

  • Time Complexity:
    Each operation—enQueue, deQueue, Front, Rear, isEmpty, and isFull—runs in O(1) time because all operations involve a fixed number of steps.

  • Space Complexity:
    The implementation uses O(k) space for the array, where k is the capacity of the circular queue.

Step-by-Step Walkthrough and Visual Example

Imagine a circular queue of capacity 3:

  1. Initialization:

    • queue = [_, _, _], head = 0, tail = 0, count = 0.
  2. After enQueue(1):

    • Insert 1 at index 0.
    • queue = [1, _, _], head = 0, tail = 1, count = 1.
  3. After enQueue(2):

    • Insert 2 at index 1.
    • queue = [1, 2, _], head = 0, tail = 2, count = 2.
  4. After enQueue(3):

    • Insert 3 at index 2.
    • queue = [1, 2, 3], head = 0, tail = 0 (wrap-around), count = 3.
  5. Attempt enQueue(4):

    • Queue is full (count == capacity), so return false.
  6. Front() and Rear():

    • Front() returns element at index 0 → 1.
    • Rear() returns element at index (tail - 1 + capacity) % capacity = (0 - 1 + 3) % 3 = 23.
  7. After deQueue():

    • Remove element at index 0.
    • queue remains [1, 2, 3] but head becomes 1 and count = 2.
  8. After enQueue(4):

    • Insert 4 at index 0 (tail position).
    • queue = [4, 2, 3], tail becomes 1, count = 3.
  9. Rear() now returns:

    • Element at index (tail - 1 + capacity) % capacity = (1 - 1 + 3) % 3 = 3 % 3 = 04.

Common Mistakes and Edge Cases

Common Mistakes

  • Confusing Empty and Full:
    Not maintaining a count or using a reserved slot can lead to ambiguous conditions. Make sure you can distinguish between the two states.

  • Incorrect Pointer Movement:
    Forgetting to use modulo arithmetic when incrementing head or tail will cause index out-of-bound errors.

  • Mismanaging the Rear Calculation:
    Since tail points to the next insertion point, always adjust to find the last element when returning Rear().

Edge Cases

  • Queue Capacity 1:
    Test the behavior when there is only one slot. Ensure that both enQueue and deQueue work correctly.

  • Multiple Wrap-Arounds:
    Enqueue and dequeue several times to ensure that the circular nature (wrap-around) of the queue works as expected.

Variations

  • Dynamic Circular Queue:
    Instead of a fixed capacity, design a circular queue that can expand dynamically.

  • Deque (Double-Ended Queue):
    Extend the design to support insertions and deletions at both the front and rear.

  • Design Stack Using Queues/Arrays:
    Practice designing other data structures using basic arrays or queues.

  • Implementing Circular Buffer:
    Similar to circular queues, a circular buffer is used in system design for buffering data streams.

TAGS
leetcode
CONTRIBUTOR
Design Gurus Team
-

GET YOUR FREE

Coding Questions Catalog

Design Gurus Newsletter - Latest from our Blog
Boost your coding skills with our essential coding questions catalog.
Take a step towards a better tech career now!
Explore Answers
Related Courses
Grokking the Coding Interview: Patterns for Coding Questions
Grokking the Coding Interview Patterns in Java, Python, JS, C++, C#, and Go. The most comprehensive course with 476 Lessons.
Grokking Modern AI Fundamentals
Master the fundamentals of AI today to lead the tech revolution of tomorrow.
Grokking Data Structures & Algorithms for Coding Interviews
Unlock Coding Interview Success: Dive Deep into Data Structures and Algorithms.
Image
One-Stop Portal For Tech Interviews.
Copyright © 2025 Design Gurus, LLC. All rights reserved.
;