Back to Technology

Complete DSA Series Part 7: Stack

January 28, 2026 Wasil Zafar 35 min read

Master the stack data structure with array and linked list implementations, expression evaluation, infix/postfix conversion, monotonic stack patterns, and FAANG interview problems.

Table of Contents

  1. Introduction
  2. Implementations
  3. Applications
  4. Monotonic Stack
  5. LeetCode Problems

Introduction to Stack

A stack is a linear data structure that follows the Last-In-First-Out (LIFO) principle. Think of it like a stack of plates - you can only add or remove plates from the top. Stacks are fundamental in computer science, used in function calls, expression parsing, undo mechanisms, and many algorithms.

Key Insight: The LIFO property makes stacks perfect for scenarios where you need to "backtrack" or process elements in reverse order of arrival. Function call stacks, browser history, and undo/redo are classic examples.

Stack Operations

Core Stack Operations

Operation Description Time
push(item) Add item to top O(1)
pop() Remove and return top item O(1)
peek()/top() Return top item without removing O(1)
isEmpty() Check if stack is empty O(1)
size() Return number of items O(1)

Stack Implementations

Array-Based Stack

Python

# Stack Implementation using Array (Python List)
# All operations O(1) amortized

class ArrayStack:
    def __init__(self, capacity=None):
        """Initialize stack with optional fixed capacity"""
        self.capacity = capacity
        self.items = []
    
    def push(self, item):
        """Add item to top - O(1) amortized"""
        if self.capacity and len(self.items) >= self.capacity:
            raise OverflowError("Stack is full")
        self.items.append(item)
    
    def pop(self):
        """Remove and return top item - O(1)"""
        if self.is_empty():
            raise IndexError("Stack is empty")
        return self.items.pop()
    
    def peek(self):
        """Return top item without removing - O(1)"""
        if self.is_empty():
            raise IndexError("Stack is empty")
        return self.items[-1]
    
    def is_empty(self):
        return len(self.items) == 0
    
    def size(self):
        return len(self.items)

# Test
stack = ArrayStack()
stack.push(1)
stack.push(2)
stack.push(3)
print(f"Peek: {stack.peek()}")  # 3
print(f"Pop: {stack.pop()}")    # 3
print(f"Size: {stack.size()}")  # 2

C++

// Stack Implementation using Array (Vector)

#include <iostream>
#include <vector>
#include <stdexcept>
using namespace std;

template <typename T>
class ArrayStack {
private:
    vector<T> items;
    int maxCapacity;
    
public:
    ArrayStack(int capacity = -1) : maxCapacity(capacity) {}
    
    void push(T item) {
        if (maxCapacity > 0 && items.size() >= maxCapacity)
            throw overflow_error("Stack is full");
        items.push_back(item);
    }
    
    T pop() {
        if (isEmpty()) throw runtime_error("Stack is empty");
        T item = items.back();
        items.pop_back();
        return item;
    }
    
    T peek() {
        if (isEmpty()) throw runtime_error("Stack is empty");
        return items.back();
    }
    
    bool isEmpty() { return items.empty(); }
    int size() { return items.size(); }
};

int main() {
    ArrayStack<int> stack;
    stack.push(1);
    stack.push(2);
    stack.push(3);
    cout << "Peek: " << stack.peek() << endl;  // 3
    cout << "Pop: " << stack.pop() << endl;    // 3
    cout << "Size: " << stack.size() << endl;  // 2
    return 0;
}

Java

// Stack Implementation using ArrayList

import java.util.ArrayList;

public class ArrayStack<T> {
    private ArrayList<T> items;
    private int maxCapacity;
    
    public ArrayStack() { this(-1); }
    
    public ArrayStack(int capacity) {
        this.items = new ArrayList<>();
        this.maxCapacity = capacity;
    }
    
    public void push(T item) {
        if (maxCapacity > 0 && items.size() >= maxCapacity)
            throw new RuntimeException("Stack is full");
        items.add(item);
    }
    
    public T pop() {
        if (isEmpty()) throw new RuntimeException("Stack is empty");
        return items.remove(items.size() - 1);
    }
    
    public T peek() {
        if (isEmpty()) throw new RuntimeException("Stack is empty");
        return items.get(items.size() - 1);
    }
    
    public boolean isEmpty() { return items.isEmpty(); }
    public int size() { return items.size(); }
    
    public static void main(String[] args) {
        ArrayStack<Integer> stack = new ArrayStack<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println("Peek: " + stack.peek());  // 3
        System.out.println("Pop: " + stack.pop());    // 3
        System.out.println("Size: " + stack.size());  // 2
    }
}

Fixed-Size Array Stack (Lower Level)

Python
# Fixed-Size Array Stack Implementation

class FixedArrayStack:
    def __init__(self, capacity):
        self.capacity = capacity
        self.array = [None] * capacity
        self.top = -1  # Index of top element
    
    def push(self, item):
        if self.is_full():
            raise OverflowError("Stack overflow")
        self.top += 1
        self.array[self.top] = item
    
    def pop(self):
        if self.is_empty():
            raise IndexError("Stack underflow")
        item = self.array[self.top]
        self.array[self.top] = None
        self.top -= 1
        return item
    
    def peek(self):
        if self.is_empty():
            raise IndexError("Stack is empty")
        return self.array[self.top]
    
    def is_empty(self):
        return self.top == -1
    
    def is_full(self):
        return self.top == self.capacity - 1
    
    def size(self):
        return self.top + 1

# Test
fixed_stack = FixedArrayStack(5)
for i in range(1, 6):
    fixed_stack.push(i * 10)
print(f"Is full: {fixed_stack.is_full()}")  # True
print(f"Pop: {fixed_stack.pop()}")  # 50
C++
// Fixed-Size Array Stack Implementation

#include <iostream>
#include <stdexcept>
using namespace std;

template <typename T>
class FixedArrayStack {
private:
    T* array;
    int capacity;
    int topIndex;
    
public:
    FixedArrayStack(int cap) : capacity(cap), topIndex(-1) {
        array = new T[capacity];
    }
    
    ~FixedArrayStack() { delete[] array; }
    
    void push(T item) {
        if (isFull()) throw overflow_error("Stack overflow");
        array[++topIndex] = item;
    }
    
    T pop() {
        if (isEmpty()) throw runtime_error("Stack underflow");
        return array[topIndex--];
    }
    
    T peek() {
        if (isEmpty()) throw runtime_error("Stack is empty");
        return array[topIndex];
    }
    
    bool isEmpty() { return topIndex == -1; }
    bool isFull() { return topIndex == capacity - 1; }
    int size() { return topIndex + 1; }
};

int main() {
    FixedArrayStack<int> stack(5);
    for (int i = 1; i <= 5; i++) stack.push(i * 10);
    cout << "Is full: " << (stack.isFull() ? "true" : "false") << endl;  // true
    cout << "Pop: " << stack.pop() << endl;  // 50
    return 0;
}
Java
// Fixed-Size Array Stack Implementation

public class FixedArrayStack<T> {
    private Object[] array;
    private int capacity;
    private int topIndex;
    
    public FixedArrayStack(int capacity) {
        this.capacity = capacity;
        this.array = new Object[capacity];
        this.topIndex = -1;
    }
    
    public void push(T item) {
        if (isFull()) throw new RuntimeException("Stack overflow");
        array[++topIndex] = item;
    }
    
    @SuppressWarnings("unchecked")
    public T pop() {
        if (isEmpty()) throw new RuntimeException("Stack underflow");
        T item = (T) array[topIndex];
        array[topIndex--] = null;
        return item;
    }
    
    @SuppressWarnings("unchecked")
    public T peek() {
        if (isEmpty()) throw new RuntimeException("Stack is empty");
        return (T) array[topIndex];
    }
    
    public boolean isEmpty() { return topIndex == -1; }
    public boolean isFull() { return topIndex == capacity - 1; }
    public int size() { return topIndex + 1; }
    
    public static void main(String[] args) {
        FixedArrayStack<Integer> stack = new FixedArrayStack<>(5);
        for (int i = 1; i <= 5; i++) stack.push(i * 10);
        System.out.println("Is full: " + stack.isFull());  // true
        System.out.println("Pop: " + stack.pop());  // 50
    }
}

Linked List-Based Stack

Python

# Stack Implementation using Linked List
# True O(1) for all operations

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class LinkedListStack:
    def __init__(self):
        self.head = None
        self._size = 0
    
    def push(self, item):
        new_node = Node(item)
        new_node.next = self.head
        self.head = new_node
        self._size += 1
    
    def pop(self):
        if self.is_empty():
            raise IndexError("Stack is empty")
        item = self.head.data
        self.head = self.head.next
        self._size -= 1
        return item
    
    def peek(self):
        if self.is_empty():
            raise IndexError("Stack is empty")
        return self.head.data
    
    def is_empty(self):
        return self.head is None
    
    def size(self):
        return self._size

# Test
ll_stack = LinkedListStack()
ll_stack.push(1)
ll_stack.push(2)
ll_stack.push(3)
print(f"Peek: {ll_stack.peek()}")  # 3
print(f"Pop: {ll_stack.pop()}")    # 3
print(f"Size: {ll_stack.size()}")  # 2

C++

// Stack Implementation using Linked List

#include <iostream>
#include <stdexcept>
using namespace std;

template <typename T>
class LinkedListStack {
private:
    struct Node {
        T data;
        Node* next;
        Node(T d) : data(d), next(nullptr) {}
    };
    
    Node* head;
    int _size;
    
public:
    LinkedListStack() : head(nullptr), _size(0) {}
    
    ~LinkedListStack() {
        while (!isEmpty()) pop();
    }
    
    void push(T item) {
        Node* newNode = new Node(item);
        newNode->next = head;
        head = newNode;
        _size++;
    }
    
    T pop() {
        if (isEmpty()) throw runtime_error("Stack is empty");
        T item = head->data;
        Node* temp = head;
        head = head->next;
        delete temp;
        _size--;
        return item;
    }
    
    T peek() {
        if (isEmpty()) throw runtime_error("Stack is empty");
        return head->data;
    }
    
    bool isEmpty() { return head == nullptr; }
    int size() { return _size; }
};

int main() {
    LinkedListStack<int> stack;
    stack.push(1);
    stack.push(2);
    stack.push(3);
    cout << "Peek: " << stack.peek() << endl;  // 3
    cout << "Pop: " << stack.pop() << endl;    // 3
    cout << "Size: " << stack.size() << endl;  // 2
    return 0;
}

Java

// Stack Implementation using Linked List

public class LinkedListStack<T> {
    private class Node {
        T data;
        Node next;
        Node(T data) { this.data = data; }
    }
    
    private Node head;
    private int size;
    
    public LinkedListStack() {
        head = null;
        size = 0;
    }
    
    public void push(T item) {
        Node newNode = new Node(item);
        newNode.next = head;
        head = newNode;
        size++;
    }
    
    public T pop() {
        if (isEmpty()) throw new RuntimeException("Stack is empty");
        T item = head.data;
        head = head.next;
        size--;
        return item;
    }
    
    public T peek() {
        if (isEmpty()) throw new RuntimeException("Stack is empty");
        return head.data;
    }
    
    public boolean isEmpty() { return head == null; }
    public int size() { return size; }
    
    public static void main(String[] args) {
        LinkedListStack<Integer> stack = new LinkedListStack<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println("Peek: " + stack.peek());  // 3
        System.out.println("Pop: " + stack.pop());    // 3
        System.out.println("Size: " + stack.size());  // 2
    }
}

Array vs Linked List Stack

Aspect Array Stack Linked List Stack
Push O(1) amortized* O(1)
Pop O(1) O(1)
Memory Contiguous, less overhead Scattered, pointer overhead
Cache Better locality Poor locality
Size Fixed or resize needed Dynamic

* O(n) worst case when resizing, but amortized O(1)

Stack Applications

Parentheses Matching

Python

# Balanced Parentheses Check
# Time: O(n), Space: O(n)

def is_balanced(expression):
    stack = []
    matching = {')': '(', ']': '[', '}': '{'}
    
    for char in expression:
        if char in '([{':
            stack.append(char)
        elif char in ')]}':
            if not stack or stack[-1] != matching[char]:
                return False
            stack.pop()
    
    return len(stack) == 0

# Test
print(is_balanced("((a+b)*(c-d))"))   # True
print(is_balanced("[(a+b)*{c-d}]"))   # True
print(is_balanced("((a+b)"))          # False
print(is_balanced("([)]"))            # False

C++

// Balanced Parentheses Check

#include <iostream>
#include <stack>
#include <unordered_map>
using namespace std;

bool isBalanced(string expression) {
    stack<char> stk;
    unordered_map<char, char> matching = {
        {')', '('}, {']', '['}, {'}', '{'}
    };
    
    for (char ch : expression) {
        if (ch == '(' || ch == '[' || ch == '{') {
            stk.push(ch);
        } else if (ch == ')' || ch == ']' || ch == '}') {
            if (stk.empty() || stk.top() != matching[ch])
                return false;
            stk.pop();
        }
    }
    return stk.empty();
}

int main() {
    cout << boolalpha;
    cout << isBalanced("((a+b)*(c-d))") << endl;  // true
    cout << isBalanced("[(a+b)*{c-d}]") << endl;  // true
    cout << isBalanced("((a+b)") << endl;         // false
    cout << isBalanced("([)]") << endl;           // false
    return 0;
}

Java

// Balanced Parentheses Check

import java.util.*;

public class ParenthesesMatching {
    public static boolean isBalanced(String expression) {
        Stack<Character> stack = new Stack<>();
        Map<Character, Character> matching = Map.of(
            ')', '(', ']', '[', '}', '{'
        );
        
        for (char ch : expression.toCharArray()) {
            if (ch == '(' || ch == '[' || ch == '{') {
                stack.push(ch);
            } else if (ch == ')' || ch == ']' || ch == '}') {
                if (stack.isEmpty() || stack.peek() != matching.get(ch))
                    return false;
                stack.pop();
            }
        }
        return stack.isEmpty();
    }
    
    public static void main(String[] args) {
        System.out.println(isBalanced("((a+b)*(c-d))"));  // true
        System.out.println(isBalanced("[(a+b)*{c-d}]"));  // true
        System.out.println(isBalanced("((a+b)"));         // false
        System.out.println(isBalanced("([)]"));           // false
    }
}

Expression Evaluation

Python - Postfix Evaluation

# Postfix (Reverse Polish Notation) Expression Evaluation
# Example: "3 4 + 5 *" means (3 + 4) * 5 = 35

def evaluate_postfix(expression):
    stack = []
    operators = {'+', '-', '*', '/', '^'}
    tokens = expression.split()
    
    for token in tokens:
        if token not in operators:
            stack.append(float(token))
        else:
            b = stack.pop()  # Second operand
            a = stack.pop()  # First operand
            
            if token == '+': stack.append(a + b)
            elif token == '-': stack.append(a - b)
            elif token == '*': stack.append(a * b)
            elif token == '/': stack.append(a / b)
            elif token == '^': stack.append(a ** b)
    
    return stack[0]

# Test
print(evaluate_postfix("3 4 +"))          # 7
print(evaluate_postfix("3 4 + 5 *"))      # 35
print(evaluate_postfix("2 3 ^ 4 +"))      # 12

C++ - Postfix Evaluation

// Postfix Expression Evaluation

#include <iostream>
#include <stack>
#include <sstream>
#include <cmath>
using namespace std;

double evaluatePostfix(string expression) {
    stack<double> stk;
    istringstream iss(expression);
    string token;
    
    while (iss >> token) {
        if (token == "+" || token == "-" || token == "*" || 
            token == "/" || token == "^") {
            double b = stk.top(); stk.pop();
            double a = stk.top(); stk.pop();
            
            if (token == "+") stk.push(a + b);
            else if (token == "-") stk.push(a - b);
            else if (token == "*") stk.push(a * b);
            else if (token == "/") stk.push(a / b);
            else if (token == "^") stk.push(pow(a, b));
        } else {
            stk.push(stod(token));
        }
    }
    return stk.top();
}

int main() {
    cout << evaluatePostfix("3 4 +") << endl;       // 7
    cout << evaluatePostfix("3 4 + 5 *") << endl;   // 35
    cout << evaluatePostfix("2 3 ^ 4 +") << endl;   // 12
    return 0;
}

Java - Postfix Evaluation

// Postfix Expression Evaluation

import java.util.*;

public class PostfixEvaluator {
    public static double evaluatePostfix(String expression) {
        Stack<Double> stack = new Stack<>();
        String[] tokens = expression.split(" ");
        Set<String> operators = Set.of("+", "-", "*", "/", "^");
        
        for (String token : tokens) {
            if (operators.contains(token)) {
                double b = stack.pop();
                double a = stack.pop();
                
                switch (token) {
                    case "+": stack.push(a + b); break;
                    case "-": stack.push(a - b); break;
                    case "*": stack.push(a * b); break;
                    case "/": stack.push(a / b); break;
                    case "^": stack.push(Math.pow(a, b)); break;
                }
            } else {
                stack.push(Double.parseDouble(token));
            }
        }
        return stack.pop();
    }
    
    public static void main(String[] args) {
        System.out.println(evaluatePostfix("3 4 +"));       // 7
        System.out.println(evaluatePostfix("3 4 + 5 *"));   // 35
        System.out.println(evaluatePostfix("2 3 ^ 4 +"));   // 12
    }
}

Python - Prefix Evaluation

# Prefix Expression Evaluation
# Process right to left

def evaluate_prefix(expression):
    stack = []
    operators = {'+', '-', '*', '/', '^'}
    tokens = expression.split()[::-1]  # Reverse
    
    for token in tokens:
        if token not in operators:
            stack.append(float(token))
        else:
            a = stack.pop()  # First operand
            b = stack.pop()  # Second operand
            
            if token == '+': stack.append(a + b)
            elif token == '-': stack.append(a - b)
            elif token == '*': stack.append(a * b)
            elif token == '/': stack.append(a / b)
            elif token == '^': stack.append(a ** b)
    
    return stack[0]

# Test
print(evaluate_prefix("+ 3 4"))       # 7
print(evaluate_prefix("* + 3 4 5"))   # 35

Infix to Postfix Conversion

Python

# Infix to Postfix Conversion (Shunting Yard Algorithm)

def infix_to_postfix(expression):
    precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3}
    right_associative = {'^'}
    output = []
    operator_stack = []
    tokens = expression.replace('(', ' ( ').replace(')', ' ) ').split()
    
    for token in tokens:
        if token.replace('.', '').lstrip('-').isdigit():
            output.append(token)
        elif token == '(':
            operator_stack.append(token)
        elif token == ')':
            while operator_stack and operator_stack[-1] != '(':
                output.append(operator_stack.pop())
            if operator_stack:
                operator_stack.pop()
        elif token in precedence:
            while (operator_stack and operator_stack[-1] != '(' and
                   operator_stack[-1] in precedence and
                   (precedence[operator_stack[-1]] > precedence[token] or
                    (precedence[operator_stack[-1]] == precedence[token] and
                     token not in right_associative))):
                output.append(operator_stack.pop())
            operator_stack.append(token)
    
    while operator_stack:
        output.append(operator_stack.pop())
    
    return ' '.join(output)

# Test
print(infix_to_postfix("3 + 4"))         # 3 4 +
print(infix_to_postfix("3 + 4 * 5"))     # 3 4 5 * +
print(infix_to_postfix("(3 + 4) * 5"))   # 3 4 + 5 *

C++

// Infix to Postfix Conversion (Shunting Yard)

#include <iostream>
#include <stack>
#include <sstream>
#include <unordered_map>
#include <set>
using namespace std;

int precedence(char op) {
    if (op == '+' || op == '-') return 1;
    if (op == '*' || op == '/') return 2;
    if (op == '^') return 3;
    return 0;
}

string infixToPostfix(string expression) {
    stack<char> opStack;
    string output;
    set<char> rightAssoc = {'^'};
    
    for (char ch : expression) {
        if (isdigit(ch)) {
            output += ch;
            output += ' ';
        } else if (ch == '(') {
            opStack.push(ch);
        } else if (ch == ')') {
            while (!opStack.empty() && opStack.top() != '(') {
                output += opStack.top();
                output += ' ';
                opStack.pop();
            }
            if (!opStack.empty()) opStack.pop();
        } else if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^') {
            while (!opStack.empty() && opStack.top() != '(' &&
                   (precedence(opStack.top()) > precedence(ch) ||
                    (precedence(opStack.top()) == precedence(ch) &&
                     rightAssoc.find(ch) == rightAssoc.end()))) {
                output += opStack.top();
                output += ' ';
                opStack.pop();
            }
            opStack.push(ch);
        }
    }
    
    while (!opStack.empty()) {
        output += opStack.top();
        output += ' ';
        opStack.pop();
    }
    return output;
}

int main() {
    cout << infixToPostfix("3+4") << endl;       // 3 4 +
    cout << infixToPostfix("3+4*5") << endl;     // 3 4 5 * +
    cout << infixToPostfix("(3+4)*5") << endl;   // 3 4 + 5 *
    return 0;
}

Java

// Infix to Postfix Conversion (Shunting Yard)

import java.util.*;

public class InfixToPostfix {
    private static int precedence(char op) {
        if (op == '+' || op == '-') return 1;
        if (op == '*' || op == '/') return 2;
        if (op == '^') return 3;
        return 0;
    }
    
    public static String convert(String expression) {
        Stack<Character> opStack = new Stack<>();
        StringBuilder output = new StringBuilder();
        Set<Character> rightAssoc = Set.of('^');
        
        for (char ch : expression.toCharArray()) {
            if (Character.isDigit(ch)) {
                output.append(ch).append(' ');
            } else if (ch == '(') {
                opStack.push(ch);
            } else if (ch == ')') {
                while (!opStack.isEmpty() && opStack.peek() != '(') {
                    output.append(opStack.pop()).append(' ');
                }
                if (!opStack.isEmpty()) opStack.pop();
            } else if ("+-*/^".indexOf(ch) != -1) {
                while (!opStack.isEmpty() && opStack.peek() != '(' &&
                       (precedence(opStack.peek()) > precedence(ch) ||
                        (precedence(opStack.peek()) == precedence(ch) &&
                         !rightAssoc.contains(ch)))) {
                    output.append(opStack.pop()).append(' ');
                }
                opStack.push(ch);
            }
        }
        
        while (!opStack.isEmpty()) {
            output.append(opStack.pop()).append(' ');
        }
        return output.toString().trim();
    }
    
    public static void main(String[] args) {
        System.out.println(convert("3+4"));       // 3 4 +
        System.out.println(convert("3+4*5"));     // 3 4 5 * +
        System.out.println(convert("(3+4)*5"));   // 3 4 + 5 *
    }
}

Monotonic Stack

A monotonic stack maintains elements in either increasing or decreasing order. It's a powerful technique for solving problems involving "next greater/smaller element" patterns.

Next Greater Element

Python

# Next Greater Element - Monotonic Decreasing Stack
# Time: O(n), Space: O(n)

def next_greater_element(nums):
    n = len(nums)
    result = [-1] * n
    stack = []  # Stack of indices
    
    for i in range(n):
        while stack and nums[stack[-1]] < nums[i]:
            result[stack.pop()] = nums[i]
        stack.append(i)
    
    return result

# Test
nums = [4, 5, 2, 10, 8]
print(next_greater_element(nums))  # [5, 10, 10, -1, -1]

C++

// Next Greater Element - Monotonic Stack

#include <iostream>
#include <vector>
#include <stack>
using namespace std;

vector<int> nextGreaterElement(vector<int>& nums) {
    int n = nums.size();
    vector<int> result(n, -1);
    stack<int> stk;  // Stack of indices
    
    for (int i = 0; i < n; i++) {
        while (!stk.empty() && nums[stk.top()] < nums[i]) {
            result[stk.top()] = nums[i];
            stk.pop();
        }
        stk.push(i);
    }
    return result;
}

int main() {
    vector<int> nums = {4, 5, 2, 10, 8};
    vector<int> nge = nextGreaterElement(nums);
    // Output: [5, 10, 10, -1, -1]
    for (int x : nge) cout << x << " ";
    return 0;
}

Java

// Next Greater Element - Monotonic Stack

import java.util.*;

public class NextGreaterElement {
    public static int[] nextGreater(int[] nums) {
        int n = nums.length;
        int[] result = new int[n];
        Arrays.fill(result, -1);
        Stack<Integer> stack = new Stack<>();  // Stack of indices
        
        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) {
                result[stack.pop()] = nums[i];
            }
            stack.push(i);
        }
        return result;
    }
    
    public static void main(String[] args) {
        int[] nums = {4, 5, 2, 10, 8};
        int[] nge = nextGreater(nums);
        System.out.println(Arrays.toString(nge));  // [5, 10, 10, -1, -1]
    }
}

Python - Circular Array

# Next Greater Element (Circular Array)

def next_greater_circular(nums):
    n = len(nums)
    result = [-1] * n
    stack = []
    
    # Process array twice to handle circular nature
    for i in range(2 * n):
        idx = i % n
        while stack and nums[stack[-1]] < nums[idx]:
            result[stack.pop()] = nums[idx]
        if i < n:
            stack.append(idx)
    
    return result

# Test
print(next_greater_circular([1, 2, 1]))  # [2, -1, 2]

Python - Next Smaller Element

# Next Smaller Element - Monotonic Increasing Stack

def next_smaller_element(nums):
    n = len(nums)
    result = [-1] * n
    stack = []
    
    for i in range(n):
        while stack and nums[stack[-1]] > nums[i]:
            result[stack.pop()] = nums[i]
        stack.append(i)
    
    return result

# Test
nums = [4, 5, 2, 10, 8]
print(next_smaller_element(nums))  # [2, 2, -1, 8, -1]

Daily Temperatures

Python

# Daily Temperatures - Classic Monotonic Stack Problem

def daily_temperatures(temperatures):
    n = len(temperatures)
    result = [0] * n
    stack = []  # Stack of indices
    
    for i in range(n):
        while stack and temperatures[stack[-1]] < temperatures[i]:
            prev_idx = stack.pop()
            result[prev_idx] = i - prev_idx
        stack.append(i)
    
    return result

# Test
temps = [73, 74, 75, 71, 69, 72, 76, 73]
print(daily_temperatures(temps))  # [1, 1, 4, 2, 1, 1, 0, 0]

C++

// Daily Temperatures - Monotonic Stack

#include <iostream>
#include <vector>
#include <stack>
using namespace std;

vector<int> dailyTemperatures(vector<int>& temps) {
    int n = temps.size();
    vector<int> result(n, 0);
    stack<int> stk;
    
    for (int i = 0; i < n; i++) {
        while (!stk.empty() && temps[stk.top()] < temps[i]) {
            int prevIdx = stk.top();
            stk.pop();
            result[prevIdx] = i - prevIdx;
        }
        stk.push(i);
    }
    return result;
}

int main() {
    vector<int> temps = {73, 74, 75, 71, 69, 72, 76, 73};
    vector<int> days = dailyTemperatures(temps);
    // Output: [1, 1, 4, 2, 1, 1, 0, 0]
    for (int d : days) cout << d << " ";
    return 0;
}

Java

// Daily Temperatures - Monotonic Stack

import java.util.*;

public class DailyTemperatures {
    public static int[] dailyTemperatures(int[] temps) {
        int n = temps.length;
        int[] result = new int[n];
        Stack<Integer> stack = new Stack<>();
        
        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && temps[stack.peek()] < temps[i]) {
                int prevIdx = stack.pop();
                result[prevIdx] = i - prevIdx;
            }
            stack.push(i);
        }
        return result;
    }
    
    public static void main(String[] args) {
        int[] temps = {73, 74, 75, 71, 69, 72, 76, 73};
        int[] days = dailyTemperatures(temps);
        System.out.println(Arrays.toString(days));  // [1, 1, 4, 2, 1, 1, 0, 0]
    }
}

LeetCode Practice Problems

Easy 20. Valid Parentheses

Determine if the input string has valid bracket pairs.

Python
# LeetCode 20 - Valid Parentheses
# Time: O(n), Space: O(n)

def isValid(s):
    stack = []
    mapping = {')': '(', ']': '[', '}': '{'}
    
    for char in s:
        if char in mapping:
            if not stack or stack[-1] != mapping[char]:
                return False
            stack.pop()
        else:
            stack.append(char)
    return len(stack) == 0

# Test
print(isValid("()[]{}"))  # True
print(isValid("([)]"))    # False
C++
bool isValid(string s) {
    stack<char> stk;
    unordered_map<char, char> mapping = {{')', '('}, {']', '['}, {'}', '{'}};
    
    for (char c : s) {
        if (mapping.count(c)) {
            if (stk.empty() || stk.top() != mapping[c])
                return false;
            stk.pop();
        } else {
            stk.push(c);
        }
    }
    return stk.empty();
}
Java
public boolean isValid(String s) {
    Stack<Character> stack = new Stack<>();
    Map<Character, Character> map = Map.of(')', '(', ']', '[', '}', '{');
    
    for (char c : s.toCharArray()) {
        if (map.containsKey(c)) {
            if (stack.isEmpty() || stack.peek() != map.get(c))
                return false;
            stack.pop();
        } else {
            stack.push(c);
        }
    }
    return stack.isEmpty();
}

Easy 155. Min Stack

Design a stack that supports getMin() in O(1).

Python
# LeetCode 155 - Min Stack

class MinStack:
    def __init__(self):
        self.stack = []
        self.min_stack = []
    
    def push(self, val):
        self.stack.append(val)
        if not self.min_stack or val <= self.min_stack[-1]:
            self.min_stack.append(val)
    
    def pop(self):
        val = self.stack.pop()
        if val == self.min_stack[-1]:
            self.min_stack.pop()
    
    def top(self):
        return self.stack[-1]
    
    def getMin(self):
        return self.min_stack[-1]
C++
class MinStack {
    stack<int> stk;
    stack<int> minStk;
    
public:
    void push(int val) {
        stk.push(val);
        if (minStk.empty() || val <= minStk.top())
            minStk.push(val);
    }
    
    void pop() {
        if (stk.top() == minStk.top())
            minStk.pop();
        stk.pop();
    }
    
    int top() { return stk.top(); }
    int getMin() { return minStk.top(); }
};
Java
class MinStack {
    Stack<Integer> stack = new Stack<>();
    Stack<Integer> minStack = new Stack<>();
    
    public void push(int val) {
        stack.push(val);
        if (minStack.isEmpty() || val <= minStack.peek())
            minStack.push(val);
    }
    
    public void pop() {
        if (stack.pop().equals(minStack.peek()))
            minStack.pop();
    }
    
    public int top() { return stack.peek(); }
    public int getMin() { return minStack.peek(); }
}

Medium 150. Evaluate Reverse Polish Notation

Evaluate postfix expression given as array of tokens.

Python
# LeetCode 150 - Evaluate Reverse Polish Notation

def evalRPN(tokens):
    stack = []
    for token in tokens:
        if token in {'+', '-', '*', '/'}:
            b, a = stack.pop(), stack.pop()
            if token == '+': stack.append(a + b)
            elif token == '-': stack.append(a - b)
            elif token == '*': stack.append(a * b)
            elif token == '/': stack.append(int(a / b))
        else:
            stack.append(int(token))
    return stack[0]

print(evalRPN(["2","1","+","3","*"]))  # 9
C++
int evalRPN(vector<string>& tokens) {
    stack<int> stk;
    for (const string& token : tokens) {
        if (token == "+" || token == "-" || token == "*" || token == "/") {
            int b = stk.top(); stk.pop();
            int a = stk.top(); stk.pop();
            if (token == "+") stk.push(a + b);
            else if (token == "-") stk.push(a - b);
            else if (token == "*") stk.push(a * b);
            else stk.push(a / b);
        } else {
            stk.push(stoi(token));
        }
    }
    return stk.top();
}
Java
public int evalRPN(String[] tokens) {
    Stack<Integer> stack = new Stack<>();
    Set<String> ops = Set.of("+", "-", "*", "/");
    
    for (String token : tokens) {
        if (ops.contains(token)) {
            int b = stack.pop(), a = stack.pop();
            switch (token) {
                case "+": stack.push(a + b); break;
                case "-": stack.push(a - b); break;
                case "*": stack.push(a * b); break;
                case "/": stack.push(a / b); break;
            }
        } else {
            stack.push(Integer.parseInt(token));
        }
    }
    return stack.pop();
}

Medium 739. Daily Temperatures

Find how many days to wait for warmer temperature.

Python
# LeetCode 739 - Daily Temperatures

def dailyTemperatures(temperatures):
    n = len(temperatures)
    result = [0] * n
    stack = []
    
    for i in range(n):
        while stack and temperatures[stack[-1]] < temperatures[i]:
            prev = stack.pop()
            result[prev] = i - prev
        stack.append(i)
    return result
C++
vector<int> dailyTemperatures(vector<int>& temps) {
    int n = temps.size();
    vector<int> result(n, 0);
    stack<int> stk;
    
    for (int i = 0; i < n; i++) {
        while (!stk.empty() && temps[stk.top()] < temps[i]) {
            result[stk.top()] = i - stk.top();
            stk.pop();
        }
        stk.push(i);
    }
    return result;
}
Java
public int[] dailyTemperatures(int[] temps) {
    int n = temps.length;
    int[] result = new int[n];
    Stack<Integer> stack = new Stack<>();
    
    for (int i = 0; i < n; i++) {
        while (!stack.isEmpty() && temps[stack.peek()] < temps[i]) {
            int prev = stack.pop();
            result[prev] = i - prev;
        }
        stack.push(i);
    }
    return result;
}

Medium 84. Largest Rectangle in Histogram

Find the largest rectangle in a histogram.

Python
# LeetCode 84 - Largest Rectangle in Histogram

def largestRectangleArea(heights):
    stack = []  # (index, height)
    max_area = 0
    
    for i, h in enumerate(heights):
        start = i
        while stack and stack[-1][1] > h:
            idx, height = stack.pop()
            max_area = max(max_area, height * (i - idx))
            start = idx
        stack.append((start, h))
    
    for idx, height in stack:
        max_area = max(max_area, height * (len(heights) - idx))
    
    return max_area

print(largestRectangleArea([2,1,5,6,2,3]))  # 10
C++
int largestRectangleArea(vector<int>& heights) {
    stack<pair<int, int>> stk;  // (index, height)
    int maxArea = 0;
    
    for (int i = 0; i < heights.size(); i++) {
        int start = i;
        while (!stk.empty() && stk.top().second > heights[i]) {
            auto [idx, h] = stk.top();
            stk.pop();
            maxArea = max(maxArea, h * (i - idx));
            start = idx;
        }
        stk.push({start, heights[i]});
    }
    
    while (!stk.empty()) {
        auto [idx, h] = stk.top();
        stk.pop();
        maxArea = max(maxArea, h * ((int)heights.size() - idx));
    }
    return maxArea;
}
Java
public int largestRectangleArea(int[] heights) {
    Stack<int[]> stack = new Stack<>();  // [index, height]
    int maxArea = 0;
    
    for (int i = 0; i < heights.length; i++) {
        int start = i;
        while (!stack.isEmpty() && stack.peek()[1] > heights[i]) {
            int[] top = stack.pop();
            maxArea = Math.max(maxArea, top[1] * (i - top[0]));
            start = top[0];
        }
        stack.push(new int[]{start, heights[i]});
    }
    
    while (!stack.isEmpty()) {
        int[] top = stack.pop();
        maxArea = Math.max(maxArea, top[1] * (heights.length - top[0]));
    }
    return maxArea;
}

Hard 32. Longest Valid Parentheses

Find the length of the longest valid parentheses substring.

Python
# LeetCode 32 - Longest Valid Parentheses

def longestValidParentheses(s):
    stack = [-1]  # Base index
    max_len = 0
    
    for i, char in enumerate(s):
        if char == '(':
            stack.append(i)
        else:
            stack.pop()
            if not stack:
                stack.append(i)  # New base
            else:
                max_len = max(max_len, i - stack[-1])
    
    return max_len

print(longestValidParentheses(")()())"))  # 4
C++
int longestValidParentheses(string s) {
    stack<int> stk;
    stk.push(-1);  // Base index
    int maxLen = 0;
    
    for (int i = 0; i < s.length(); i++) {
        if (s[i] == '(') {
            stk.push(i);
        } else {
            stk.pop();
            if (stk.empty()) {
                stk.push(i);  // New base
            } else {
                maxLen = max(maxLen, i - stk.top());
            }
        }
    }
    return maxLen;
}
Java
public int longestValidParentheses(String s) {
    Stack<Integer> stack = new Stack<>();
    stack.push(-1);  // Base index
    int maxLen = 0;
    
    for (int i = 0; i < s.length(); i++) {
        if (s.charAt(i) == '(') {
            stack.push(i);
        } else {
            stack.pop();
            if (stack.isEmpty()) {
                stack.push(i);  // New base
            } else {
                maxLen = Math.max(maxLen, i - stack.peek());
            }
        }
    }
    return maxLen;
}
Technology