Subject to introduce
Force button 622: leetcode-cn.com/problems/de…
Method one: arrays
According to the problem description, the data structure used in this problem should be a ring connected end to end.
There is no ring structure in any data structure, but you can use one-dimensional array simulation to build a virtual ring by manipulating the index of the array. Many complex data structures can be implemented using arrays.
TailIndex = (headIndex + count − 1) mod Capacity for a fixed size array, any position can be the head of the queue. If you know the length of the queue, you can calculate the tail position by using the following formula: tailIndex = (headIndex + count − 1) mod Capacity
Capacity is the array length, count is the queue length, headIndex and tailIndex are the index of the head and tail of the queue respectively. The following figure shows an example of a loop queue using an array.
Based on the above principles, list each attribute of the loop queue and explain its meaning.
-
Queue: A fixed-size array that holds the elements of a circular queue.
-
HeadIndex: an integer that holds the index of the head of the queue.
-
Count: The current length of the loop queue, i.e. the number of elements in the loop queue. Use hadIndex and count to calculate the index of the end-of-queue element, so end-of-queue attributes are not required.
-
Capacity: Indicates the capacity of the circular queue, that is, the maximum number of elements that can be held in the queue. This property is not required because the queue capacity can be obtained through the array property, but because it is often used, we choose to keep it. This way you don’t have to fetch the capacity every time len(queue) is called in Python. But in Java, it’s more efficient to get the capacity through queue.length. For consistency, this property is retained in both scenarios.
The code is as follows:
class MyCircularQueue {
private int[] queue;// Store queue elements
private int headIndex;/ / head index
private int count;// Number of current queue nodes
private int capacity;// The size of the current queue
/** Initialize your data structure here. Set the size of the queue to be k. */
public MyCircularQueue(int k) {
this.capacity = k;
this.queue = new int[k];
this.headIndex = 0;
this.count = 0;
}
/** * queue */
public boolean enQueue(int value) {
// The queue is full
if (this.count == this.capacity)
return false;
// Computes the next index of the trailing index
this.queue[(this.headIndex + this.count) % this.capacity] = value;
this.count += 1;
return true;
}
/** ** queue */
public boolean deQueue(a) {
// The queue element is empty
if (this.count == 0)
return false;
// Adjust the header index
this.headIndex = (this.headIndex + 1) % this.capacity;
// The number of queue elements is reduced by one
this.count -= 1;
return true;
}
/** * gets the header element, the element corresponding to the header index */
public int Front(a) {
if (this.count == 0)
return -1;
return this.queue[this.headIndex];
}
/** * gets the trailing element, the element corresponding to the trailing index */
public int Rear(a) {
if (this.count == 0)
return -1;
int tailIndex = (this.headIndex + this.count - 1) % this.capacity;
return this.queue[tailIndex];
}
/** * Check whether the queue is empty */
public boolean isEmpty(a) {
return (this.count == 0);
}
/** * Check whether the queue is full */
public boolean isFull(a) {
return (this.count == this.capacity); }}Copy the code
We can also use double Pointers, one to the head element and one to the tail element, as follows:
public class MyCircularQueue {
private int[] data; // The length of the loop queue is fixed
private int head;
private int tail;
private int size;
public MyCircularQueue(int k) { // constructor
data = new int[k];
head = -1;
tail = -1;
size = k;
}
/** Inserts the element into the loop queue. Returns true */ if the operation succeeds
public boolean enQueue(int value) {
// If the queue is full, new elements cannot be added successfully, return false
if (isFull()) {
return false;
}
if (isEmpty()) {
head = 0;
}
tail = (tail + 1) % size; // Calculate the value of the next tail
data[tail] = value;
return true;
}
/** Removes an element from the loop queue. Returns true */ if the operation succeeds
public boolean deQueue(a) {
// If the queue is empty, the element cannot be deleted successfully, return false
if (isEmpty()) {
return false;
}
if (head == tail) { // There is only one element
head = -1;
tail = -1;
} else {
head = (head + 1) % size; // head moves by 1
}
return true;
}
/** Retrieve elements from the head of the team. If the queue is empty, -1 */ is returned
public int Front(a) {
if (isEmpty()) {
return -1;
}
return data[head];
}
/** Get the last element of the queue. If the queue is empty, -1 */ is returned
public int Rear(a) {
if (isEmpty()) {
return -1;
}
return data[tail];
}
/** Check if the loop queue is empty */
public boolean isEmpty(a) {
return head == -1;
}
/** Check if the loop queue is full */
public boolean isFull(a) {
return (tail + 1) % size == head; }}Copy the code
Complexity analysis
-
Time complexity: O(1). In this data structure, all methods have constant time complexity.
-
Space complexity: O(N), where N is the pre-allocated capacity of the queue. This pre-allocated space is held for the entire life of the circular queue.