Implement Stack using Queues

🏠 ⬅️ ➡️

Implement a last-in-first-out (LIFO) stack using only two queues. The implemented stack should support all the functions of a normal stack (push, top, pop, and empty).

Implement the MyStack class:

  • void push(int x) Pushes element x to the top of the stack.
  • int pop() Removes the element on the top of the stack and returns it.
  • int top() Returns the element on the top of the stack.
  • boolean empty() Returns true if the stack is empty, false otherwise.

Notes:

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

Example 1:

Input [ "MyStack ", "push ", "push ", "top ", "pop ", "empty "] [[], [1], [2], [], [], []] Output [null, null, null, 2, 2, false]

Explanation MyStack myStack = new MyStack(); myStack.push(1); myStack.push(2); myStack.top(); // return 2 myStack.pop(); // return 2 myStack.empty(); // return False

Constraints:

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

Follow-up: Can you implement the stack using only one queue?


Note: This problem is from LeetCode.
Compiled
Executed
Correct
program main
    ! This program implements a last-in-first-out (LIFO) stack using only two queues.
    implicit none

    type :: MyStack
        private
        integer, allocatable :: q1(:), q2(:)
        integer :: size
    contains
        procedure :: push => push_impl
        procedure :: pop => pop_impl
        procedure :: top => top_impl
        procedure :: empty => empty_impl
    end type MyStack

    interface MyStack
        module procedure constructor
    end interface MyStack

contains

    function constructor() result(stack)
        type(MyStack) :: stack

        allocate(stack%q1(0))
        allocate(stack%q2(0))
        stack%size = 0
    end function constructor

    subroutine push_impl(this, x)
        class(MyStack), intent(inout) :: this
        integer, value :: x

        if (allocated(this%q1)) then
            call move_alloc(this%q1, this%q2)
        else
            allocate(this%q1(0))
        end if
        allocate(this%q1(this%size + 1))
        this%q1(this%size + 1) = x
        this%size = this%size + 1
    end subroutine push_impl

    function pop_impl(this) result(x)
        class(MyStack), intent(inout) :: this
        integer :: x

        if (.not. allocated(this%q1)) then
            error stop 'Error: pop called on empty stack.'
        end if
        x = this%q1(this%size)
        this%size = this%size - 1
        if (this%size == 0) then
            deallocate(this%q1)
            if (allocated(this%q2)) then
                call move_alloc(this%q2, this%q1)
            end if
        end if
    end function pop_impl

    function top_impl(this) result(x)
        class(MyStack), intent(in) :: this
        integer :: x

        if (.not. allocated(this%q1)) then
            error stop 'Error: top called on empty stack.'
        end if
        x = this%q1(this%size)
    end function top_impl

    logical function empty_impl(this)
        class(MyStack), intent(in) :: this

        empty_impl = .not. allocated(this%q1)
    end function empty_impl

end program main
Compiled
Executed
Correct
module MyStack
    implicit none
    private
    type :: MyStack_t
        integer :: size = 0
        integer, allocatable :: queue(:)
    end type MyStack_t

    interface MyStack
        module procedure constructor
    end interface MyStack

contains

    function constructor() result(this)
        type(MyStack_t) :: this

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

    subroutine push(this, x)
        class(MyStack_t), intent(inout) :: this
        integer, intent(in) :: x

        this%size = this%size + 1
        allocate(this%queue(this%size))
        this%queue(this%size) = x
    end subroutine push

    function top(this) result(x)
        class(MyStack_t), intent(in) :: this
        integer :: x

        x = this%queue(this%size)
    end function top

    function pop(this) result(x)
        class(MyStack_t), intent(inout) :: this
        integer :: x

        x = this%queue(this%size)
        this%size = this%size - 1
        deallocate(this%queue(this%size + 1))
    end function pop

    function empty(this) result(x)
        class(MyStack_t), intent(in) :: this
        logical :: x

        x = this%size == 0
    end function empty
end module MyStack

program main
    use MyStack
    implicit none
    type(MyStack_t) :: stack
    integer :: x

    ! Test case 1:
    call stack%push(1)
    call stack%push(2)
    x = stack%top()
    write (*,*) x
    x = stack%pop()
    write (*,*) x
    x = stack%empty()
    write (*,*) x

    ! Test case 2:
    call stack%push(3)
    call stack%push(4)
    x = stack%top()
    write (*,*) x
    x = stack%pop()
    write (*,*) x
    x = stack%empty()
    write (*,*) x

    ! Test case 3:
    call stack%push(5)
    call stack%push(6)
    x = stack%top()
    write (*,*) x
    x = stack%pop()
    write (*,*) x
    x = stack%empty()
    write (*,*) x
end program main
🌐 Data from online sources
from collections import deque

class MyStack:

    def __init__(self):
        self.q1 = deque()
        self.q2 = deque()

    def push(self, x: int) -> None:
        self.q2.append(x)
        while self.q1:
            self.q2.append(self.q1.popleft())
        self.q1, self.q2 = self.q2, self.q1

    def pop(self) -> int:
        return self.q1.popleft()

    def top(self) -> int:
        return self.q1[0]

    def empty(self) -> bool:
        return not self.q1

We have two queues q1 and q2, where we will store the elements. For every push operation, we first push the new element into q2, then move all the elements in the q1 to q2, and then swap both queues. The pop and top operations will always operate on q1, which maintains the elements in the reverse order, simulating the LIFO order of a stack. The empty operation simply checks if q1 is empty.

The time complexity for push is O(n), while the time complexities for top, pop, and empty are O(1).

🌐 Data from online sources
#include <queue>

class MyStack {
public:
    std::queue<int> q1, q2;

    void push(int x) {
        q2.push(x);
        while (!q1.empty()) {
            q2.push(q1.front());
            q1.pop();
        }
        std::swap(q1, q2);
    }

    int pop() {
        int top = q1.front();
        q1.pop();
        return top;
    }

    int top() {
        return q1.front();
    }

    bool empty() {
        return q1.empty();
    }
};

We have two queues q1 and q2, where we will store the elements. For every push operation, we first push the new element into q2, then move all the elements in the q1 to q2, and then swap both queues. The pop and top operations will always operate on q1, which maintains the elements in the reverse order, simulating the LIFO order of a stack. The empty operation simply checks if q1 is empty.

The time complexity for push is O(n), while the time complexities for top, pop, and empty are O(1).