641. Design Circular Deque

641. Design Circular Deque

Design your implementation of the circular double-ended queue (deque).

Your implementation should support following operations:

  • MyCircularDeque(k): Constructor, set the size of the deque to be k.
  • insertFront(): Adds an item at the front of Deque. Return true if the operation is successful.
  • insertLast(): Adds an item at the rear of Deque. Return true if the operation is successful.
  • deleteFront(): Deletes an item from the front of Deque. Return true if the operation is successful.
  • deleteLast(): Deletes an item from the rear of Deque. Return true if the operation is successful.
  • getFront(): Gets the front item from the Deque. If the deque is empty, return -1.
  • getRear(): Gets the last item from Deque. If the deque is empty, return -1.
  • isEmpty(): Checks whether Deque is empty or not. 
  • isFull(): Checks whether Deque is full or not.

Example:

MyCircularDeque circularDeque = new MycircularDeque(3); // set the size to be 3
circularDeque.insertLast(1);			// return true
circularDeque.insertLast(2);			// return true
circularDeque.insertFront(3);			// return true
circularDeque.insertFront(4);			// return false, the queue is full
circularDeque.getRear();  			// return 2
circularDeque.isFull();				// return true
circularDeque.deleteLast();			// return true
circularDeque.insertFront(4);			// return true
circularDeque.getFront();			// return 4

Note:

  • All values will be in the range of [0, 1000].
  • The number of operations will be in the range of [1, 1000].
  • Please do not use the built-in Deque library.

State the problem (as you understand it): 

  • Implement a circular double-ended queue

Solve examples that are big enough and are normal cases (manually to figure out the general solution): 

Ask clarification questions:

State assumptions:

Consider several test cases (edge cases, base cases):

See if a Data Structure fits the problem:

  1. use an array
  2. use a doubly linked list 

See if an Algorithm fits the problem:

  1. ad-hoc algorithm

Extract the core problem:

  • implement a circular double-ended queue

Try breaking it down into subproblems:

Explain Potential Solutions (see solutin section):

Other solutions:

Compare solutions:

  • easier to use linked list since for array you might need to handle edge cases depending on the initial index you use for the front and rear pointer. For example, if you choose 0 and -1 to be the initial values for front and rear pointers respectively, then you'd need to handle the edge case: add front -> get rear. But if you experiment with different indices, you would find that using last position for front pointer and first position for rear pointer has no edge cases

Follow Up (TODO):

Solution 1:


Ideas: 

  • insert elements to the front starting from the end position of the array
  • insert elements to the rear starting from the start position of the array

Steps:

  1. create instance variables
    1. use int array to keep track of elements
    2. use int size to keep track of current size of array
    3. use int front to keep track of front insert index
    4. use int rear to keep track of rear insert index
  2. implement insertFront method
    1. return false if array is full
    2. set the given value at the current front index
    3. increment front index
    4. increment size
  3. implement deleteFront method
    1. return false if array is empty
    2. increment front index
    3. decrement size

Validate the correctness (of your pseudocode with a test case):

Data Structure:

  • use an array

Time Complexity:

  • O(1)

Space Complexity:

  • O(k), where k is the number of elements in the buffer
class MyCircularDeque {
    
    private int[] buffer;
    private int size = 0;
    private int front;
    private int rear = 0;

    /** Initialize your data structure here. Set the size of the deque to be k. */
    public MyCircularDeque(int k) {
        this.buffer = new int[k];
        this.front = k - 1;
    }
    
    /** Adds an item at the front of Deque. Return true if the operation is successful. */
    public boolean insertFront(int value) {
        if (this.isFull()) {
            return false;
        }     
        
        this.buffer[front] = value;
        this.front = (this.front - 1 + this.buffer.length) % this.buffer.length; 
        this.size++;
        
        return true;
    }
    
    /** Adds an item at the rear of Deque. Return true if the operation is successful. */
    public boolean insertLast(int value) {
        if (this.isFull()) {
            return false;
        }
        
        this.buffer[rear] = value;
        this.rear = (this.rear + 1) % this.buffer.length;
        this.size++;
        
        return true;
    }
    
    /** Deletes an item from the front of Deque. Return true if the operation is successful. */
    public boolean deleteFront() {
        if (this.isEmpty()) {
            return false;
        }
        
        this.front = (this.front + 1) % this.buffer.length; 
        this.size--;
        return true;
    }
    
    /** Deletes an item from the rear of Deque. Return true if the operation is successful. */
    public boolean deleteLast() {
        if (this.isEmpty()) {
            return false;
        }
        
        this.rear = (this.rear - 1 + this.buffer.length) % this.buffer.length;    
        this.size--;
        return true;
    }
    
    /** Get the front item from the deque. */
    public int getFront() {
        if (this.isEmpty()) {
            return -1;
        }    
        
        return this.buffer[(this.front + 1) % this.buffer.length];
    }
    
    /** Get the last item from the deque. */
    public int getRear() {
        if (this.isEmpty()) {
            return -1;
        }   
        
        return this.buffer[(this.rear - 1 + this.buffer.length) % this.buffer.length];
    }
    
    /** Checks whether the circular deque is empty or not. */
    public boolean isEmpty() {
        return this.size == 0;    
    }
    
    /** Checks whether the circular deque is full or not. */
    public boolean isFull() {
        return this.size == this.buffer.length;    
    }
}

/**
 * Your MyCircularDeque object will be instantiated and called as such:
 * MyCircularDeque obj = new MyCircularDeque(k);
 * boolean param_1 = obj.insertFront(value);
 * boolean param_2 = obj.insertLast(value);
 * boolean param_3 = obj.deleteFront();
 * boolean param_4 = obj.deleteLast();
 * int param_5 = obj.getFront();
 * int param_6 = obj.getRear();
 * boolean param_7 = obj.isEmpty();
 * boolean param_8 = obj.isFull();
 */

Test your code again to make sure you don't have any bugs.

Solution 2:


Ideas: 

  • use a doubly linked list with a head and tail pointer to keep track of elements

Steps:

  1. create instance variables
    1. use int currSize to keep track of current number of elements
    2. use int maxSize to keep track of max number of elements
    3. use a dummy node to represent head pointer
    4. use a dummy node to represent tail pointer
  2. implement insertFront method
    1. add new node with given value before the head node
  3. implement deleteFront method
    1. remove the node before the head node

Validate the correctness (of your pseudocode with a test case):

Data Structure:

  • use a doubly linked list

Time Complexity:

  • O(1)

Space Complexity:

  • O(1)
class MyCircularDeque {
    
    private int currSize = 0;
    private int maxSize = 0;
    private Node head = new Node(-1);
    private Node tail = new Node(-1);

    /** Initialize your data structure here. Set the size of the deque to be k. */
    public MyCircularDeque(int k) {
        this.maxSize = k;        
        
        this.head.prev = tail;
        this.tail.next = this.head;
    }
    
    /** Adds an item at the front of Deque. Return true if the operation is successful. */
    public boolean insertFront(int value) {
        if (this.isFull()) {
            return false;
        }    
        
        Node node = new Node(value);
        node.next = this.head;
        node.prev = this.head.prev;
        this.head.prev.next = node;
        this.head.prev = node;     
        
        this.currSize++;
        return true;
    }
    
    /** Adds an item at the rear of Deque. Return true if the operation is successful. */
    public boolean insertLast(int value) {
        if (this.isFull()) {
            return false;
        }    
        
        Node node = new Node(value);
        node.next = this.tail.next;
        node.prev = this.tail;
        this.tail.next.prev = node;
        this.tail.next = node;
        
        this.currSize++;
        return true;
    }
    
    /** Deletes an item from the front of Deque. Return true if the operation is successful. */
    public boolean deleteFront() {
        if (this.isEmpty()) {
            return false;    
        }      
        
        this.head.prev.prev.next = this.head;
        this.head.prev = this.head.prev.prev;
        this.currSize--;
        
        return true;
    }
    
    /** Deletes an item from the rear of Deque. Return true if the operation is successful. */
    public boolean deleteLast() {
        if (this.isEmpty()) {
            return false;    
        }    
        
        this.tail.next.next.prev = this.tail;
        this.tail.next = this.tail.next.next;
        this.currSize--;
        
        return true;
    }
    
    /** Get the front item from the deque. */
    public int getFront() {
        return this.head.prev.val;
    }
    
    /** Get the last item from the deque. */
    public int getRear() {      
        return this.tail.next.val;
    }
    
    /** Checks whether the circular deque is empty or not. */
    public boolean isEmpty() {
        return this.currSize == 0;    
    }
    
    /** Checks whether the circular deque is full or not. */
    public boolean isFull() {
        return this.currSize == this.maxSize;    
    }
    
    private class Node {
        private int val;
        private Node prev;
        private Node next;
        
        public Node(int val) {
            this.val = val;
        }
    }
}

/**
 * Your MyCircularDeque object will be instantiated and called as such:
 * MyCircularDeque obj = new MyCircularDeque(k);
 * boolean param_1 = obj.insertFront(value);
 * boolean param_2 = obj.insertLast(value);
 * boolean param_3 = obj.deleteFront();
 * boolean param_4 = obj.deleteLast();
 * int param_5 = obj.getFront();
 * int param_6 = obj.getRear();
 * boolean param_7 = obj.isEmpty();
 * boolean param_8 = obj.isFull();
 */

Test your code again to make sure you don't have any bugs.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值