Minimal, copy-paste C++ for parentheses matching, expression evaluation, nested structures, and monotonic stack.

Contents

Parentheses Matching

Use stack’s LIFO property to match opening and closing brackets in reverse order.

bool isValid(string s) {
    stack<char> st;
    unordered_map<char, char> map = {
        {'}', '{'}, {']', '['}, {')', '('}
    };
    
    for(char c: s) {
        if(c == '{' || c == '[' || c == '(') {
            st.push(c);
        } else {
            if(st.empty() || st.top() != map[c]) return false;
            st.pop();
        }
    }
    return st.empty();
}
ID Title Link Solution
20 Valid Parentheses Link Solution
921 Minimum Add to Make Valid Parentheses Link Solution
1249 Minimum Remove to Make Valid Parentheses Link Solution

Expression Evaluation

Use stack to handle operator precedence and parentheses in mathematical expressions.

int calculate(string s) {
    stack<int> stk;
    int result = 0, num = 0, sign = 1;
    
    for(char c: s) {
        if(isdigit(c)) {
            num = num * 10 + (c - '0');
        } else if(c == '+' || c == '-') {
            result += sign * num;
            sign = (c == '+') ? 1 : -1;
            num = 0;
        } else if(c == '(') {
            stk.push(result);
            stk.push(sign);
            result = 0;
            sign = 1;
        } else if(c == ')') {
            result += sign * num;
            result *= stk.top(); stk.pop();
            result += stk.top(); stk.pop();
            num = 0;
        }
    }
    return result + sign * num;
}
ID Title Link Solution
150 Evaluate Reverse Polish Notation Link Solution
224 Basic Calculator Link Solution
227 Basic Calculator II Link Solution
772 Basic Calculator III Link Solution

Nested Structure Processing

Use stack to process nested structures like strings, expressions, or function calls.

string decodeString(string s) {
    stack<string> st;
    string curr = "";
    int k = 0;
    
    for(char c: s) {
        if(isdigit(c)) {
            k = k * 10 + (c - '0');
        } else if(c == '[') {
            st.push(to_string(k));
            st.push(curr);
            curr = "";
            k = 0;
        } else if(c == ']') {
            string prev = st.top(); st.pop();
            int count = stoi(st.top()); st.pop();
            string temp = "";
            for(int i = 0; i < count; i++) temp += curr;
            curr = prev + temp;
        } else {
            curr += c;
        }
    }
    return curr;
}
ID Title Link Solution
394 Decode String Link Solution
636 Exclusive Time of Functions Link Solution
71 Simplify Path Link -

Monotonic Stack & Deque Patterns

Eight common patterns that cover nearly all monotonic stack / deque problems. Recognize the pattern by this clue: “find the next/previous smaller/greater element, or determine how far an element can extend.”


Pattern 1: Next Greater Element

Find the first element to the right that is strictly greater. Use a monotonic decreasing stack (top is smallest).

vector<int> nextGreater(vector<int>& nums) {
    int n = nums.size();
    vector<int> ans(n, -1);
    stack<int> st;

    for (int i = 0; i < n; i++) {
        while (!st.empty() && nums[st.top()] < nums[i]) {
            ans[st.top()] = nums[i];
            st.pop();
        }
        st.push(i);
    }
    return ans;
}
ID Title Link Solution
496 Next Greater Element I Link Solution
739 Daily Temperatures Link Solution
503 Next Greater Element II Link Solution
901 Online Stock Span Link -
1944 Visible People in Queue Link Solution

Pattern 2: Next Smaller Element

Same idea but reversed comparison. Use a monotonic increasing stack (top is largest).

vector<int> nextSmaller(vector<int>& nums) {
    int n = nums.size();
    vector<int> ans(n, -1);
    stack<int> st;

    for (int i = 0; i < n; i++) {
        while (!st.empty() && nums[st.top()] > nums[i]) {
            ans[st.top()] = nums[i];
            st.pop();
        }
        st.push(i);
    }
    return ans;
}
ID Title Link Solution
1475 Final Prices With Special Discount Link -
84 Largest Rectangle in Histogram Link Solution

Pattern 3: Previous Greater / Smaller Element

Instead of looking right, find the left boundary. Scan left-to-right, the stack top is the previous greater/smaller.

Finding both previous smaller and next smaller defines the range where an element is the minimum – critical for range-based counting.

// Previous smaller element (strictly)
vector<int> prevSmaller(vector<int>& nums) {
    int n = nums.size();
    vector<int> ans(n, -1);
    stack<int> st;

    for (int i = 0; i < n; i++) {
        while (!st.empty() && nums[st.top()] >= nums[i])
            st.pop();
        if (!st.empty()) ans[i] = st.top();
        st.push(i);
    }
    return ans;
}
ID Title Link Solution
907 Sum of Subarray Minimums Link -
2104 Sum of Subarray Ranges Link -

Pattern 4: Histogram Expansion

Each bar expands left and right until hitting a shorter bar. Width = right_smaller - left_smaller - 1.

Combine next smaller (right boundary) and previous smaller (left boundary) to compute the maximum rectangle.

int largestRectangleArea(vector<int>& heights) {
    int n = heights.size(), ans = 0;
    stack<int> st;

    for (int i = 0; i <= n; i++) {
        int h = (i == n) ? 0 : heights[i];
        while (!st.empty() && heights[st.top()] > h) {
            int height = heights[st.top()]; st.pop();
            int width = st.empty() ? i : i - st.top() - 1;
            ans = max(ans, height * width);
        }
        st.push(i);
    }
    return ans;
}
ID Title Link Solution
84 Largest Rectangle in Histogram Link Solution
42 Trapping Rain Water Link Solution

Pattern 5: Matrix → Histogram Trick

Convert each row of a binary matrix into a histogram of heights, then run the histogram algorithm on each row.

int maximalRectangle(vector<vector<char>>& matrix) {
    if (matrix.empty()) return 0;
    int m = matrix.size(), n = matrix[0].size(), ans = 0;
    vector<int> heights(n, 0);

    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++)
            heights[j] = (matrix[i][j] == '1') ? heights[j] + 1 : 0;
        ans = max(ans, largestRectangleArea(heights));
    }
    return ans;
}
ID Title Link Solution
85 Maximal Rectangle Link -

Pattern 6: Monotonic Deque (Sliding Window Max/Min)

Maintain a monotonic decreasing deque of indices for sliding window maximum. Remove smaller elements from back, remove out-of-window elements from front.

vector<int> maxSlidingWindow(vector<int>& nums, int k) {
    deque<int> dq;
    vector<int> ans;

    for (int i = 0; i < (int)nums.size(); i++) {
        while (!dq.empty() && nums[dq.back()] <= nums[i])
            dq.pop_back();
        dq.push_back(i);
        if (dq.front() <= i - k) dq.pop_front();
        if (i >= k - 1) ans.push_back(nums[dq.front()]);
    }
    return ans;
}
ID Title Link Solution
239 Sliding Window Maximum Link Solution

Pattern 7: Greedy Stack (Remove Digits / Lexicographic Optimization)

Use the stack to maintain an optimal ordering. While the stack top is worse than the current element and we still have removals left, pop it.

string removeKdigits(string num, int k) {
    string st;
    for (char c : num) {
        while (k > 0 && !st.empty() && st.back() > c) {
            st.pop_back();
            k--;
        }
        st.push_back(c);
    }
    while (k-- > 0) st.pop_back();

    // strip leading zeros
    int start = 0;
    while (start < (int)st.size() && st[start] == '0') start++;
    string ans = st.substr(start);
    return ans.empty() ? "0" : ans;
}
ID Title Link Solution
402 Remove K Digits Link -
316 Remove Duplicate Letters Link Solution

Pattern 8: Prefix Sum + Monotonic Deque

Find the shortest subarray with sum at least k. Combine prefix sums with an increasing deque to efficiently find the closest valid left boundary.

int shortestSubarray(vector<int>& nums, int k) {
    int n = nums.size(), ans = n + 1;
    vector<long long> pre(n + 1, 0);
    for (int i = 0; i < n; i++) pre[i + 1] = pre[i] + nums[i];

    deque<int> dq;
    for (int i = 0; i <= n; i++) {
        while (!dq.empty() && pre[i] - pre[dq.front()] >= k) {
            ans = min(ans, i - dq.front());
            dq.pop_front();
        }
        while (!dq.empty() && pre[dq.back()] >= pre[i])
            dq.pop_back();
        dq.push_back(i);
    }
    return ans <= n ? ans : -1;
}
ID Title Link Solution
862 Shortest Subarray with Sum at Least K Link Solution

Practice Roadmap

Follow this progression from basics to advanced:

Step Focus Problems
1 Basics Next Greater Element I (496), Daily Temperatures (739)
2 Core Stack Mastery Next Greater Element II (503), Online Stock Span (901)
3 Histogram Largest Rectangle in Histogram (84), Maximal Rectangle (85)
4 Advanced Range Counting Sum of Subarray Minimums (907), Sum of Subarray Ranges (2104)
5 Deque + Advanced Sliding Window Maximum (239), Shortest Subarray with Sum at Least K (862)

Stack for State Management

Use stack to save and restore state when processing nested or hierarchical structures.

// Example: Tracking function call stack
void processLogs(vector<string>& logs) {
    stack<pair<int, int>> st;  // {function_id, start_time}
    vector<int> result(n, 0);
    
    for(string& log: logs) {
        // Parse log entry
        if(isStart) {
            st.push({id, time});
        } else {
            auto [funcId, startTime] = st.top();
            st.pop();
            int duration = time - startTime + 1;
            result[funcId] += duration;
            
            // Subtract from parent if exists
            if(!st.empty()) {
                result[st.top().first] -= duration;
            }
        }
    }
}
ID Title Link Solution
636 Exclusive Time of Functions Link Solution
394 Decode String Link Solution

Stack Design (Min/Max Stack)

Maintaining extra information (like minimums or frequencies) alongside the primary stack data.

class MinStack {
    stack<int> stk, minStk;
public:
    void push(int val) {
        stk.push(val);
        if (minStk.empty()) minStk.push(val);
        else minStk.push(min(minStk.top(), val));
    }
    void pop() { stk.pop(); minStk.pop(); }
    int top() { return stk.top(); }
    int getMin() { return minStk.top(); }
};
ID Title Link Solution
155 Min Stack Link Solution
716 Max Stack Link -

Key Patterns

  1. LIFO Property: Stack naturally handles reverse-order matching (parentheses, brackets)
  2. State Preservation: Save state before entering nested structures, restore after exiting
  3. Operator Precedence: Use stack to defer low-precedence operations
  4. Monotonic Order: Maintain sorted order to efficiently find extrema
  5. Index Tracking: Store indices instead of values when you need position information

When to Use Stack

  • ✅ Matching problems (parentheses, brackets, tags)
  • ✅ Expression evaluation with precedence
  • ✅ Nested structure processing
  • ✅ Finding next/previous greater/smaller elements
  • ✅ Reversing order or processing in reverse
  • ✅ Undo/redo functionality
  • ✅ Function call tracking

Common Mistakes

  1. Forgetting to check empty stack before st.top() or st.pop()
  2. Wrong stack order when pushing/popping multiple values
  3. Not resetting state after processing elements
  4. Index vs value confusion in monotonic stack problems

More templates