1. Implement Queue with Help of Array
 static class QueueArr{
        static int arr[];
        static int size;
        static int rare;

        //Constructor
        QueueArr(int n){
            arr = new int[n];
            size = n;
            rare = -1;
        }
        public static boolean empty() {
            if (rare == -1) {
                return true;
            }
            return false;
        }
        public static void add(int data) {
            if (rare == size-1) {
                System.out.println("full fill");
            }
            rare++;
            arr[rare] = data;
        }
        public static int remove() {
            if (empty()) {
                System.out.println("empty hn");
                return -1;
            }
            int front  = arr[0];
            for (int i = 0; i < rare; i++) {
                arr[i] = arr[i+1];
            }
            rare--;
            return front;
        }
        public static int top() {
            if (empty()) {
                System.out.println("Empty");
                return -1;
            }
            return arr[0];
        }
    }

  1. Circular Queue

Rare = (rare + 1) % size → for rotate rare from last index of arrary to first index for adding data in queue

Front = (front + 1) % size

static class Circqueue{
        static int arr[];
        static int size;
        static int rare;
        static int front;

        //constructor
        Circqueue(int n){
            arr = new int[n];
            size = n;
            rare = -1;
            front = -1; 
        }
        public static boolean empty() {
            if (rare == -1 && front == -1) {
                return true;
            }
            return false;
        }
        public static boolean full() {
            if ((rare+1)%size == front) {
                return true;
            }
            return false;
        }
        public static void add(int data) {
            if (full()) {
                return;
            }
            if (front == -1) {
                front = 0;
            }
            rare = (rare+1)%size;
            arr[rare] = data;
        }
        public static int remove() {
            if (empty()) {
                return -1;
            }
            int res = arr[front];
            if (rare == front) {
                rare = front = -1;
            }else{
                front = (front+1)%size;
            }
            return front;  
        }
        public static int peek() {
            if (empty()) {
                return -1;
            }
            return arr[front];
        }
    }
  1. Implement Queue with Help of LinkedLists
static class Node{
        int data;
        Node next;

        Node(int data){
            this.data = data;
            this.next = null;
        }
    }

    static class LLQueue{
        static Node head = null;
        static Node tail = null;
         public static boolean empty() {
            if (head == null && tail == null) {
                return true;
            }
            return false;
         }
         public static void add(int data) {
            Node newnode = new Node(data);
            if (head == null) {
                head = tail = newnode;
                return;
            }
            tail.next = newnode;
            tail = newnode;
         }
         public static int remove() {
            if (empty()) {
                return -1;
            }
            int front = head.data;
            if (tail == head) { // Single element
                tail = head = null;
            }else{
                head = head.next;
            }
            return front;
         }
         public static int peek() {
            if (empty()) {
                return -1;
            }
            return head.data;
         }
    }
  1. Queues Using two Stacks
static Stack<Integer> s1 = new Stack<>();
    static Stack<Integer> s2 = new Stack<>();

    //Is Empty
    public static boolean isEmpty() {
        return s1.isEmpty();
    }
    //Add -> O(n)
    public static void add(int data) {
        //Step - 1 => s1 jab tak khali ni hn tabh tak s1 ke saare element s2 mein rakh do 
        while (!s1.isEmpty()) {
            s2.push(s1.pop()); //s1 ke ele ko pop karwa ke s2 mein daald diye
        }
        //Step - 2 => s1 mein push kardo
        s1.push(data);

        //Step - 3 =>Wapas se s2 ke ele ko utha ke s1 mein daaldena
        while (!s2.isEmpty()) {
            s1.push(s2.pop());
        }
    }
    //Remove =>O(1)
    public static int remove() {
        if (isEmpty()) {
            System.out.println("Queue is empty");
            return -1;
        }
        return s1.pop();
    }

    //Peek => O(1)
    public static int peek() {
         if (isEmpty()) {
            System.out.println("Empty");
            return -1;
         }
         return s1.peek();
    }

  1. Stacks Using two Queues

  1. Next Greater Element
        int ans[] = new int[nums2.length];
        Stack<Integer> s = new Stack<>();
        for(int i = nums2.length-1 ; i >= 0 ; i--){

            while(!s.isEmpty() && s.peek() < nums2[i]){
                s.pop();
            }

            if(s.isEmpty()){
                ans[i] = -1;
            }else{
                ans[i] = s.peek();
            }

            s.push(nums2[i]);
        }
  1. Previous Smaller Element
//Brute Force
public int[] prevSmaller(int[] A) {
        int ans[] = new int[A.length];
        for (int i = 0; i < A.length; i++) {
            for (int j = i-1; j >= 0; j--) {
                if (A[i]>A[j]) {
                    ans[i] = A[j];
                    break;
                }else{
                    ans[i] = -1;
                }
            }
        }
        ans[0]=-1;
        return ans;
    }