Stack with Maximum

Last Updated : 13 Sep, 2025

Design a SpecialStack that supports push(x), pop(), peek(), isEmpty(), and getMax() in O(1) time.

  • push(x) → add element x
  • pop() → remove and return top element; return -1 if empty
  • peek() → return top element without removing; -1 if empty
  • isEmpty() → return true if stack is empty, else false
  • getMax() → return maximum element; -1 if empty

All operations must run in O(1).

Examples

Input: operations[] = [push(2), push(3), peek(), pop(), getMax(), push(1), getMax()]
Output: [3, 2, 2]
Explanation:
push(2): Stack is [2]
push(3): Stack is [2, 3]
peek(): Top element is 3
pop(): Removes top element 3, stack is [2]
getMax(): Maximum element is 2
push(1): Stack is [2, 1]
getMax(): Maximum element is 2

Try It Yourself
redirect icon

[Approach 1] Using an Auxiliary Stack - O(1) Time and O(n) Space

The idea is to use two stacks: a main stack to store the actual elements and an auxiliary stack to track the maximum elements. The auxiliary stack always has its top as the current maximum.

How to Maintain Maximum Element?

Whenever we push an element into the main stack, we also update the auxiliary stack:

  • If the auxiliary stack is empty, or the new element is greater than or equal to the current maximum (top of the auxiliary stack), then we push this new element into the auxiliary stack as well.
  • Otherwise, we push the same maximum value (the top of the auxiliary stack) again, so that both stacks remain the same size, and the auxiliary stack always has the current maximum at its top.

Whenever we pop an element from the main stack, we also pop from the auxiliary stack. This way, both stacks always stay in sync. Thus, at any time, the top of the auxiliary stack represents the maximum element of the main stack, and getMax() can be returned in constant time.

C++
#include <iostream>
#include <stack>
using namespace std;

class SpecialStack {
    stack<int> st; 
    stack<int> maxStack; 

public:

    // Add an element to the stack
    void push(int x) {
        st.push(x);

        // Maintain maxStack for O(1) getMax()
        if (maxStack.empty() || x >= maxStack.top())
            maxStack.push(x);
        else
            maxStack.push(maxStack.top());
    }

    // Remove the top element from the stack
    int pop() {
        if (st.empty()) return -1;

        int top = st.top();
        st.pop();
        maxStack.pop();
        return top;
    }

    // Get the top element
    int peek() {
        return st.empty() ? -1 : st.top();
    }

    // Check if stack is empty
    bool isEmpty() {
        return st.empty();
    }

    // Get the maximum element
    int getMax() {
        return maxStack.empty() ? -1 : maxStack.top();
    }
};

int main() {
    SpecialStack st;

    st.push(18);
    st.push(19);
    st.push(29);
    st.push(15);
    
    cout << st.peek() << "\n";    
    cout << st.getMax() << "\n";  
    
    st.push(16);
    cout << st.pop() << "\n";     
    cout << st.pop() << "\n";     
    cout << st.getMax() << "\n";  

    return 0;
}
Java
import java.util.Stack;

class SpecialStack {
    Stack<Integer> st = new Stack<>();
    Stack<Integer> maxSt = new Stack<>();

    public void push(int x) {
        st.push(x);

        // If maxSt is empty or x is greater than top of maxSt, push x
        if (maxSt.isEmpty() || x >= maxSt.peek()) {
            maxSt.push(x);
        } else {
         
            // Otherwise, push the top of maxSt to keep maximum unchanged
            maxSt.push(maxSt.peek());
        }
    }

    // Pop the top element
    public int pop() {
        if (st.isEmpty()) {
            return -1;
        }

        int poppedElement = st.pop();
        maxSt.pop();
        return poppedElement;
    }

    // Return the top element without removing
    public int peek() {
        return st.isEmpty() ? -1 : st.peek();
    }

    // Check if the stack is empty
    public boolean isEmpty() {
        return st.isEmpty();
    }

    // Return maximum element
    public int getMax() {
        return maxSt.isEmpty() ? -1 : maxSt.peek();
    }

    public static void main(String[] args) {
        SpecialStack st = new SpecialStack();

        st.push(18);
        st.push(19);
        st.push(29);
        st.push(15);
        System.out.println(st.peek());
        System.out.println(st.getMax());
        st.push(16);
        System.out.println(st.pop());
        System.out.println(st.pop());
        System.out.println(st.getMax());
    }
}
Python
class SpecialStack:
    def __init__(self):
        self.st = []
        self.maxSt = []

    def push(self, x):
        self.st.append(x)

        # If maxSt is empty or x is greater than top of maxSt, push x
        if not self.maxSt or x >= self.maxSt[-1]:
            self.maxSt.append(x)
        else:
            # Otherwise, push the top of maxSt to keep maximum unchanged
            self.maxSt.append(self.maxSt[-1])

    # Pop the top element
    def pop(self):
        if not self.st:
            return -1

        poppedElement = self.st.pop()
        self.maxSt.pop()
        return poppedElement

    # Return the top element without removing
    def peek(self):
        return -1 if not self.st else self.st[-1]

    # Check if the stack is empty
    def isEmpty(self):
        return len(self.st) == 0

    # Return maximum element
    def getMax(self):
        return -1 if not self.maxSt else self.maxSt[-1]


if __name__ == "__main__":
    st = SpecialStack()

    st.push(18)
    st.push(19)
    st.push(29)
    st.push(15)
    print(st.peek())
    print(st.getMax())
    st.push(16)
    print(st.pop())
    print(st.pop())
    print(st.getMax())
C#
using System;
using System.Collections.Generic;

class SpecialStack {
    Stack<int> st = new Stack<int>();
    Stack<int> maxSt = new Stack<int>();

    public void push(int x) {
        st.Push(x);

        // If maxSt is empty or x is greater than top of maxSt, push x
        if (maxSt.Count == 0 || x >= maxSt.Peek()) {
            maxSt.Push(x);
        } else {
            // Otherwise, push top of maxSt to keep maximum unchanged
            maxSt.Push(maxSt.Peek());
        }
    }

    // Pop the top element
    public int pop() {
        if (st.Count == 0) {
            return -1;
        }

        int poppedElement = st.Peek();
        st.Pop();
        maxSt.Pop();
        return poppedElement;
    }

    // Return the top element without removing
    public int peek() {
        return st.Count == 0 ? -1 : st.Peek();
    }

    // Check if the stack is empty
    public bool isEmpty() {
        return st.Count == 0;
    }

    // Return maximum element
    public int getMax() {
        return maxSt.Count == 0 ? -1 : maxSt.Peek();
    }

    static void Main(string[] args) {
        SpecialStack st = new SpecialStack();

        st.push(18);
        st.push(19);
        st.push(29);
        st.push(15);
        Console.WriteLine(st.peek());
        Console.WriteLine(st.getMax());
        st.push(16);
        Console.WriteLine(st.pop());
        Console.WriteLine(st.pop());
        Console.WriteLine(st.getMax());
    }
}
JavaScript
class SpecialStack {
    constructor() {
        this.st = [];
        this.maxSt = [];
    }

    push(x) {
        this.st.push(x);

        // If maxSt is empty or x is greater than top of maxSt, push x
        if (this.maxSt.length === 0 || x >= this.maxSt[this.maxSt.length - 1]) {
            this.maxSt.push(x);
        } else {
            
            // Otherwise, push top of maxSt to keep maximum unchanged
            this.maxSt.push(this.maxSt[this.maxSt.length - 1]);
        }
    }

    // Pop the top element
    pop() {
        if (this.st.length === 0) {
            return -1;
        }

        let poppedElement = this.st[this.st.length - 1];
        this.st.pop();
        this.maxSt.pop();
        return poppedElement;
    }

    // Return the top element without removing
    peek() {
        return this.st.length === 0 ? -1 : this.st[this.st.length - 1];
    }

    // Check if the stack is empty
    isEmpty() {
        return this.st.length === 0;
    }

    // Return maximum element
    getMax() {
        return this.maxSt.length === 0 ? -1 : this.maxSt[this.maxSt.length - 1];
    }
}

// Driver Code
const st = new SpecialStack();
st.push(18);
st.push(19);
st.push(29);
st.push(15);
console.log(st.peek());
console.log(st.getMax());
st.push(16);
console.log(st.pop());
console.log(st.pop());
console.log(st.getMax());

Output
15
29
16
15
29

[Approach 2] Using a Pair in Stack - O(1) Time and O(n) Space

The idea is to use a single stack where each entry is stored as a pair. The first part of the pair represents the actual element, while the second part keeps track of the maximum value in the stack up to that point. This way, every push automatically updates the running maximum, and the top of the stack always gives us direct access to the current maximum.

How to Maintain Maximum Element?

Whenever we push an element:

  • If the stack is empty, we push (element, element) since the element itself is the maximum.
  • Otherwise, we compare the new element with the current maximum (the second value at the top of the stack). The new pair becomes (element, max(element, currentMax)).

Whenever we pop, we simply remove the top pair. With this structure, the top of the stack not only gives the current element but also the maximum till that point. Hence, getMax() is just returning the second value of the top pair, which works in constant time.

C++
#include <iostream>
#include <stack>
using namespace std;

class SpecialStack {
    
    // Each element stores {value, maximum till now}
    stack<pair<int, int>> st;

public:

    // Push element onto the stack
    void push(int x) {
        if (st.empty()) {
          
            // If stack is empty, both value and maxTillNow are x
            st.push({x, x});
        } else {
          
            // Otherwise, compute the new maxTillNow
            int currentMax = max(x, st.top().second);
            st.push({x, currentMax});
        }
    }

    // Pop the top element from the stack
    int pop() {
        if (st.empty()) {
            return -1;
        }
        int poppedElement = st.top().first;
        st.pop();
        return poppedElement;
    }

    // Return the top element of the stack
    int peek() {
        if (st.empty()) {
            return -1;
        }
        return st.top().first;
    }

    // Check if the stack is empty
    bool isEmpty() {
        return st.empty();
    }

    // Get the maximum element in the stack
    int getMax() {
        if (st.empty()) {
            return -1;
        }
        return st.top().second;
    }
};

int main() {
    SpecialStack st;
    
    st.push(18);
    st.push(19);
    st.push(29);
    st.push(15);
    cout << st.peek() << "\n";      
    cout << st.getMax() << "\n";   
    st.push(16);
    cout << st.pop() << "\n";      
    cout << st.pop() << "\n";       
    cout << st.getMax() << "\n";   
    return 0;
}
Java
import java.util.Stack;

class SpecialStack {
    
    // Each element stores {value, maximum till now}
    private Stack<int[]> st = new Stack<>();

    // Push element onto the stack
    public void push(int x) {
        if (st.isEmpty()) {
       
            // If stack is empty, both value and maxTillNow are x
            st.push(new int[]{x, x});
        } else {
       
            // Otherwise, compute the new maxTillNow
            int currentMax = Math.max(x, st.peek()[1]);
            st.push(new int[]{x, currentMax});
        }
    }

    // Pop the top element from the stack
    public int pop() {
        if (st.isEmpty()) {
            return -1;
        }
        int poppedElement = st.peek()[0];
        st.pop();
        return poppedElement;
    }

    // Return the top element of the stack
    public int peek() {
        if (st.isEmpty()) {
            return -1;
        }
        return st.peek()[0];
    }

    // Check if the stack is empty
    public boolean isEmpty() {
        return st.isEmpty();
    }

    // Get the maximum element in the stack
    public int getMax() {
        if (st.isEmpty()) {
            return -1;
        }
        return st.peek()[1];
    }

    public static void main(String[] args) {
        SpecialStack st = new SpecialStack();

        st.push(18);
        st.push(19);
        st.push(29);
        st.push(15);
        System.out.println(st.peek());
        System.out.println(st.getMax());
        st.push(16);
        System.out.println(st.pop());
        System.out.println(st.pop());
        System.out.println(st.getMax());
    }
}
Python
class SpecialStack:
    
    # Each element stores (value, maximum till now)
    def __init__(self):
        self.st = []

    # Push element onto the stack
    def push(self, x):
        if not self.st:
          
            # If stack is empty, both value and maxTillNow are x
            self.st.append((x, x))
        else:
          
            # Otherwise, compute the new maxTillNow
            currentMax = max(x, self.st[-1][1])
            self.st.append((x, currentMax))

    # Pop the top element from the stack
    def pop(self):
        if not self.st:
            return -1
        poppedElement = self.st[-1][0]
        self.st.pop()
        return poppedElement

    # Return the top element of the stack
    def peek(self):
        if not self.st:
            return -1
        return self.st[-1][0]

    # Check if the stack is empty
    def isEmpty(self):
        return len(self.st) == 0

    # Get the maximum element in the stack
    def getMax(self):
        if not self.st:
            return -1
        return self.st[-1][1]


if __name__ == "__main__":
    st = SpecialStack()

    st.push(18)
    st.push(19)
    st.push(29)
    st.push(15)
    print(st.peek())
    print(st.getMax())
    st.push(16)
    print(st.pop())
    print(st.pop())
    print(st.getMax())
C#
using System;
using System.Collections.Generic;

class SpecialStack {
    
    // Each element in the stack stores (value, maximum till now)
    private Stack<(int, int)> st = new Stack<(int, int)>();

    // Push element onto the stack
    public void push(int x) {
        if (st.Count == 0) {
            // If stack is empty, both value and maxTillNow are x
            st.Push((x, x));
        } else {
            // Otherwise, compute the new maxTillNow
            int currentMax = Math.Max(x, st.Peek().Item2);
            st.Push((x, currentMax));
        }
    }

    // Pop the top element from the stack
    public int pop() {
        if (st.Count == 0) {
            return -1;
        }
        int poppedElement = st.Peek().Item1;
        st.Pop();
        return poppedElement;
    }

    // Return the top element of the stack
    public int peek() {
        if (st.Count == 0) {
            return -1;
        }
        return st.Peek().Item1;
    }

    // Check if the stack is empty
    public bool isEmpty() {
        return st.Count == 0;
    }

    // Get the maximum element in the stack
    public int getMax() {
        if (st.Count == 0) {
            return -1;
        }
        return st.Peek().Item2;
    }

    public static void Main(string[] args) {
        SpecialStack st = new SpecialStack();

        st.push(18);
        st.push(19);
        st.push(29);
        st.push(15);
        Console.WriteLine(st.peek());
        Console.WriteLine(st.getMax());
        st.push(16);
        Console.WriteLine(st.pop());
        Console.WriteLine(st.pop());
        Console.WriteLine(st.getMax());
    }
}
JavaScript
class SpecialStack {
    constructor() {
     
        // Each element in the stack stores [value, maximum till now]
        this.st = [];
    }

    // Push element onto the stack
    push(x) {
        if (this.st.length === 0) {
       
            // If stack is empty, both value and maxTillNow are x
            this.st.push([x, x]);
        } else {
       
            // Otherwise, compute the new maxTillNow
            let currentMax = Math.max(x, this.st[this.st.length - 1][1]);
            this.st.push([x, currentMax]);
        }
    }

    // Pop the top element from the stack
    pop() {
        if (this.st.length === 0) return -1;
        let poppedElement = this.st[this.st.length - 1][0];
        this.st.pop();
        return poppedElement;
    }

    // Return the top element of the stack
    peek() {
        if (this.st.length === 0) return -1;
        return this.st[this.st.length - 1][0];
    }

    // Check if the stack is empty
    isEmpty() {
        return this.st.length === 0;
    }

    // Get the maximum element in the stack
    getMax() {
        if (this.st.length === 0) return -1;
        return this.st[this.st.length - 1][1];
    }
}

// Driver Code
let st = new SpecialStack();
st.push(18);
st.push(19);
st.push(29);
st.push(15);
console.log(st.peek());
console.log(st.getMax());
st.push(16);
console.log(st.pop());
console.log(st.pop());
console.log(st.getMax());

Output
15
29
16
15
29

[Expected Approach] Using Mathematical Encoding - O(1) Time and O(1) Space

The idea is to maintain a single variable for the current maximum and encode any new element that is greater than the current maximum before pushing it onto the stack. This encoded value allows us to store both the new element and the previous maximum in one number. While popping, if the value is encoded, we decode it to retrieve the previous maximum, ensuring that getMax() always returns the correct maximum in constant time without using extra space.

There are two main steps to handle the maximum while using the encoding approach:

Case 1: While pushing a value

  • If the new element x is less than or equal to the current maximum (maxElement), push it normally.
  • If x is greater than maxElement, encode it before pushing: encoded = (2 * x − maxElement) and Push encoded onto the stack.
  • Update maxElement = x to reflect the new maximum.

Case 2: While popping a value

  • If the popped value is less than or equal to maxElement, it is a normal value.
  • If the popped value is greater than maxElement, it is an encoded value.
  • Retrieve the previous maximum using: previousMax = (2 * maxElement − encoded) and update maxElement = previousMax.
C++
#include <iostream>
#include <stack>
using namespace std;

class SpecialStack {
    stack<int> st; 
    int maxElement; 

public:
    void push(int x) {
        if (st.empty()) {
            st.push(x);
            maxElement = x;
        } else if (x <= maxElement) {
            st.push(x);
        } else {
           
            // Encode the value and update maxElement
            int encoded = 2 * x - maxElement;
            st.push(encoded);
            maxElement = x;
        }
    }

    // Pop the top element from the stack
    int pop() {
        if (st.empty()) return -1;
       
        int topVal = st.top();
        st.pop();

        if (topVal <= maxElement) {
            return topVal;
        } else {
            int actualValue = maxElement;
            int previousMax = 2 * maxElement - topVal;
            maxElement = previousMax;
            return actualValue;
        }
    }

    // Return the top element of the stack
    int peek() {
        if (st.empty()) return -1;

        int topVal = st.top();
        return (topVal <= maxElement) ? topVal : maxElement;
    }

    // Check if the stack is empty
    bool isEmpty() {
        return st.empty();
    }

    // Get the maximum element in the stack
    int getMax() {
        if (st.empty()) return -1;
        return maxElement;
    }
};

int main() {
    SpecialStack st;

    st.push(18);
    st.push(19);
    st.push(29);
    st.push(15);
    cout << st.peek() << "\n";    
    cout << st.getMax() << "\n";  
    st.push(16);
    cout << st.pop() << "\n";    
    cout << st.pop() << "\n";    
    cout << st.getMax() << "\n";  

    return 0;
}
Java
import java.util.Stack;

class SpecialStack {
    Stack<Integer> st = new Stack<>();
    int maxElement;

    // Push element onto the stack
    void push(int x) {
        if (st.isEmpty()) {
            st.push(x);
            maxElement = x;
        } else if (x <= maxElement) {
            st.push(x);
        } else {
            
            // Encode the value and update maxElement
            int encoded = 2 * x - maxElement;
            st.push(encoded);
            maxElement = x;
        }
    }

    // Pop the top element from the stack
    int pop() {
        if (st.isEmpty()) return -1;

        int topVal = st.pop();
        if (topVal <= maxElement) {
            return topVal;
        } else {
            int actualValue = maxElement;
            int previousMax = 2 * maxElement - topVal;
            maxElement = previousMax;
            return actualValue;
        }
    }

    // Return the top element of the stack
    int peek() {
        if (st.isEmpty()) return -1;

        int topVal = st.peek();
        return (topVal <= maxElement) ? topVal : maxElement;
    }

    // Check if the stack is empty
    boolean isEmpty() {
        return st.isEmpty();
    }

    // Get the maximum element in the stack
    int getMax() {
        if (st.isEmpty()) return -1;
        return maxElement;
    }

    public static void main(String[] args) {
        SpecialStack st = new SpecialStack();

        st.push(18);
        st.push(19);
        st.push(29);
        st.push(15);
        System.out.println(st.peek());
        System.out.println(st.getMax());
        st.push(16);
        System.out.println(st.pop());
        System.out.println(st.pop());
        System.out.println(st.getMax());
    }
}
Python
class SpecialStack:
    def __init__(self):
        self.st = []
        self.maxElement = None

    # Push element onto the stack
    def push(self, x):
        if not self.st:
            self.st.append(x)
            self.maxElement = x
        elif x <= self.maxElement:
            self.st.append(x)
        else:
         
            # Encode the value and update maxElement
            encoded = 2 * x - self.maxElement
            self.st.append(encoded)
            self.maxElement = x

    # Pop the top element from the stack
    def pop(self):
        if not self.st:
            return -1

        topVal = self.st.pop()
        if topVal <= self.maxElement:
            return topVal
        else:
            actualValue = self.maxElement
            previousMax = 2 * self.maxElement - topVal
            self.maxElement = previousMax
            return actualValue

    # Return the top element of the stack
    def peek(self):
        if not self.st:
            return -1

        topVal = self.st[-1]
        return topVal if topVal <= self.maxElement else self.maxElement

    # Check if the stack is empty
    def isEmpty(self):
        return len(self.st) == 0

    # Get the maximum element in the stack
    def getMax(self):
        if not self.st:
            return -1
        return self.maxElement


if __name__ == "__main__":
    st = SpecialStack()
    st.push(18)
    st.push(19)
    st.push(29)
    st.push(15)
    print(st.peek())
    print(st.getMax())
    st.push(16)
    print(st.pop())
    print(st.pop())
    print(st.getMax())
C#
using System;
using System.Collections.Generic;

class SpecialStack {
    Stack<int> st = new Stack<int>();
    int maxElement;

    // Push element onto the stack
    public void push(int x) {
        if (st.Count == 0) {
            st.Push(x);
            maxElement = x;
        } else if (x <= maxElement) {
            st.Push(x);
        } else {
          
            // Encode the value and update maxElement
            int encoded = 2 * x - maxElement;
            st.Push(encoded);
            maxElement = x;
        }
    }

    // Pop the top element from the stack
    public int pop() {
        if (st.Count == 0) {
            return -1;
        }

        int topVal = st.Pop();
        if (topVal <= maxElement) {
            return topVal;
        } else {
            int actualValue = maxElement;
            int previousMax = 2 * maxElement - topVal;
            maxElement = previousMax;
            return actualValue;
        }
    }

    // Return the top element of the stack
    public int peek() {
        if (st.Count == 0) {
            return -1;
        }

        int topVal = st.Peek();
        return (topVal <= maxElement) ? topVal : maxElement;
    }

    // Check if the stack is empty
    public bool IsEmpty() {
        return st.Count == 0;
    }

    // Get the maximum element in the stack
    public int getMax() {
        if (st.Count == 0) {
            return -1;
        }
        return maxElement;
    }

    public static void Main() {
        SpecialStack st = new SpecialStack();

        st.push(18);
        st.push(19);
        st.push(29);
        st.push(15);
        Console.WriteLine(st.peek());
        Console.WriteLine(st.getMax());
        st.push(16);
        Console.WriteLine(st.pop());
        Console.WriteLine(st.pop());
        Console.WriteLine(st.getMax());
    }
}
JavaScript
class SpecialStack {
    constructor() {
        this.st = [];
        this.maxElement = null;
    }

    // Push element onto the stack
    push(x) {
        if (this.st.length === 0) {
            this.st.push(x);
            this.maxElement = x;
        } else if (x <= this.maxElement) {
            this.st.push(x);
        } else {
            // Encode the value and update maxElement
            let encoded = 2 * x - this.maxElement;
            this.st.push(encoded);
            this.maxElement = x;
        }
    }

    // Pop the top element from the stack
    pop() {
        if (this.st.length === 0) {
            return -1;
        }

        let topVal = this.st.pop();
        if (topVal <= this.maxElement) {
            return topVal;
        } else {
            let actualValue = this.maxElement;
            let previousMax = 2 * this.maxElement - topVal;
            this.maxElement = previousMax;
            return actualValue;
        }
    }

    // Return the top element of the stack
    peek() {
        if (this.st.length === 0) {
            return -1;
        }

        let topVal = this.st[this.st.length - 1];
        return topVal <= this.maxElement ? topVal : this.maxElement;
    }

    // Check if the stack is empty
    isEmpty() {
        return this.st.length === 0;
    }

    // Get the maximum element in the stack
    getMax() {
        if (this.st.length === 0) {
            return -1;
        }
        return this.maxElement;
    }
}

// Driver Code
let st = new SpecialStack();
st.push(18);
st.push(19);
st.push(29);
st.push(15);
console.log(st.peek());
console.log(st.getMax());
st.push(16);
console.log(st.pop());
console.log(st.pop());
console.log(st.getMax());

Output
15
29
16
15
29
Comment