Implement Queue using Stacks

🏠 ⬅️ ➡️

Implement a first in first out (FIFO) queue using only two stacks. The implemented queue should support all the functions of a normal queue (push, peek, pop, and empty).

Implement the MyQueue class:

  • void push(int x) Pushes element x to the back of the queue.
  • int pop() Removes the element from the front of the queue and returns it.
  • int peek() Returns the element at the front of the queue.
  • boolean empty() Returns true if the queue is empty, false otherwise.

Notes:

  • You must use only standard operations of a stack, which means only push to top, peek/pop from top, size, and is empty operations are valid.
  • Depending on your language, the stack may not be supported natively. You may simulate a stack using a list or deque (double-ended queue) as long as you use only a stack's standard operations.

Example 1:

Input [ "MyQueue ", "push ", "push ", "peek ", "pop ", "empty "] [[], [1], [2], [], [], []] Output [null, null, null, 1, 1, false]

Explanation MyQueue myQueue = new MyQueue(); myQueue.push(1); // queue is: [1] myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue) myQueue.peek(); // return 1 myQueue.pop(); // return 1, queue is [2] myQueue.empty(); // return false

Constraints:

  • 1 <= x <= 9
  • At most 100 calls will be made to push, pop, peek, and empty.
  • All the calls to pop and peek are valid.

Follow-up: Can you implement the queue such that each operation is amortized O(1) time complexity? In other words, performing n operations will take overall O(n) time even if one of those operations may take longer.


Note: This problem is from LeetCode.
Compiled
Executed
Correct
program main
    implicit none

    type :: MyQueue
        private
        integer, allocatable :: stack(:)
        integer :: size = 0
    contains
        procedure :: push => push_impl
        procedure :: pop => pop_impl
        procedure :: peek => peek_impl
        procedure :: empty => empty_impl
    end type MyQueue

    interface MyQueue
        module procedure constructor
    end interface MyQueue

contains

    function constructor() result(queue)
        type(MyQueue) :: queue

        allocate(queue%stack(0))
    end function constructor

    subroutine push_impl(queue, x)
        class(MyQueue), intent(inout) :: queue
        integer, value :: x

        queue%size = queue%size + 1
        allocate(queue%stack(queue%size))
        queue%stack(queue%size) = x
    end subroutine push_impl

    function pop_impl(queue) result(x)
        class(MyQueue), intent(inout) :: queue
        integer :: x

        if (queue%empty()) then
            error stop 'cannot pop from an empty queue'
        end if

        x = queue%stack(queue%size)
        deallocate(queue%stack(queue%size))
        queue%size = queue%size - 1
    end function pop_impl

    function peek_impl(queue) result(x)
        class(MyQueue), intent(in) :: queue
        integer :: x

        if (queue%empty()) then
            error stop 'cannot peek from an empty queue'
        end if

        x = queue%stack(queue%size)
    end function peek_impl

    logical function empty_impl(queue) result(empty)
        class(MyQueue), intent(in) :: queue

        empty = queue%size == 0
    end function empty_impl

end program main
Compiled
Executed
Correct
module MyQueue

! Declare the stacks used to implement the queue
integer :: stack1(100), stack2(100)
integer :: top1, top2

! Declare the functions of the queue
contains

! Push an element to the back of the queue
subroutine push(x)
integer, intent(in) :: x
! If the first stack is empty, push the element to the first stack
if (top1 == 0) then
    top1 = 1
    stack1(top1) = x
else
    ! If the first stack is not empty, push the element to the second stack
    top2 = top2 + 1
    stack2(top2) = x
end if
end subroutine push

! Pop an element from the front of the queue
function pop() result(x)
integer :: x
! If the first stack is empty, pop the element from the second stack
if (top1 == 0) then
    top2 = top2 - 1
    x = stack2(top2 + 1)
else
    ! If the first stack is not empty, pop the element from the first stack
    top1 = top1 - 1
    x = stack1(top1 + 1)
end if
end function pop

! Peek at the element at the front of the queue
function peek() result(x)
integer :: x
! If the first stack is empty, peek at the element from the second stack
if (top1 == 0) then
    x = stack2(top2 + 1)
else
    ! If the first stack is not empty, peek at the element from the first stack
    x = stack1(top1 + 1)
end if
end function peek

! Check if the queue is empty
function empty() result(x)
logical :: x
! If both stacks are empty, the queue is empty
if (top1 == 0 .and. top2 == 0) then
    x = .true.
else
    x = .false.
end if
end function empty

end module MyQueue

! Test the queue with the given examples
program test
use MyQueue
implicit none

! Test case 1: Push and pop
call push(1)
call push(2)
call push(3)
call push(4)
call push(5)
call push(6)
call push(7)
call push(8)
call push(9)
call push(10)
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call pop()
call
🌐 Data from online sources
class MyQueue:

    def __init__(self):
        self.stack1 = []
        self.stack2 = []

    def push(self, x: int) -> None:
        self.stack1.append(x)

    def pop(self) -> int:
        if not self.stack2:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        return self.stack2.pop()

    def peek(self) -> int:
        if not self.stack2:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        return self.stack2[-1]

    def empty(self) -> bool:
        return not self.stack1 and not self.stack2

We can use two stacks(stack1 and stack2) to simulate a queue's functionality. Each time we push an element into the queue, we push it to stack1.

When we need to pop or peek the front element, we check if stack2 is empty; if so, pop all elements from stack1 and push them to stack2. The front element of the queue then would be on the top of the stack2. If stack2 is not empty, just pop or peek the top element of stack2.

To check if the queue is empty, we just need to check if both the stacks are empty.

By doing this, we are maintaining stack2 as the reversed version of stack1, which allows us to access the elements in the correct order for a queue (FIFO).

🌐 Data from online sources
class MyQueue {
public:
    stack<int> stack1, stack2;

    MyQueue() {
    }

    void push(int x) {
        stack1.push(x);
    }

    int pop() {
        if (stack2.empty()) {
            while (!stack1.empty()) {
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        int top_element = stack2.top();
        stack2.pop();
        return top_element;
    }

    int peek() {
        if (stack2.empty()) {
            while (!stack1.empty()) {
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        return stack2.top();
    }

    bool empty() {
        return stack1.empty() && stack2.empty();
    }
};

We can use two stacks(stack1 and stack2) to simulate a queue's functionality. Each time we push an element into the queue, we push it to stack1.

When we need to pop or peek the front element, we check if stack2 is empty; if so, pop all elements from stack1 and push them to stack2. The front element of the queue then would be on the top of the stack2. If stack2 is not empty, just pop or peek the top element of stack2.

To check if the queue is empty, we just need to check if both the stacks are empty.

By doing this, we are maintaining stack2 as the reversed version of stack1, which allows us to access the elements in the correct order for a queue (FIFO).