7 Stack Patterns That Show Up in Almost Every FAANG Interview (With Code)
I ignored stack questions for two years of my career. Then I bombed an interview because of exactly that, and had to relearn everything the hard way.

7 Stack Patterns That Show Up in Almost Every FAANG Interview (With Code)
Here’s something nobody tells you when you start prepping for interviews: stacks feel “too simple” to take seriously.
You learn push, pop, peek. You solve “Valid Parentheses” once. You feel smart. You move on to trees and graphs, because we think interviews ends up on these topics only.
And then, three months later, you’re in a real interview, the interviewer says something like “can you find, for every day, how many days you’d have to wait for a warmer temperature?” — and your brain just… stalls.
Not because the problem is hard. Because you never built the muscle to recognize that this is a stack problem in a disguise.
I’ve been on both sides of this — as the candidate who froze, and later as the interviewer watching other people freeze the exact same way. And it’s almost always the same story: people know what a stack is, but they’ve never mapped out the actual patterns stacks are used for. So they can recite the definition but can’t spot the pattern live, under pressure, with someone watching them type.
This article is my attempt to fix that gap. No fluff about LIFO being “like a stack of plates” for five paragraphs. Just the patterns, the code, and the exact questions I’d tell a junior engineer to practice if they had two weekends before an interview.
Quick honest question before we start — how many of you have solved “Valid Parentheses” but skipped everything else in the stack section because it felt “done”? Drop a comment, I want to know if this was just me.
A 60-Second Refresher (Skip if You Already Know This)
A stack is Last In, First Out — LIFO. The last thing you pushed is the first thing you pop.
const stack = [];
stack.push(10);
stack.push(20);
stack.push(30);
console.log(stack.pop()); // 30 - last one in, first one out
console.log(stack); // [10, 20]In JavaScript, a plain array works fine as a stack because push() and pop() are both O(1) at the end of the array.
Here’s the mistake I’ve seen even experienced devs make in interviews: using shift() or unshift() on an array and calling it a stack. Those operations are O(n) because the whole array has to shift its indices. If your interviewer is watching your time complexity, this alone can tank your answer. Always push/pop from the end, never the front.
Alright, refresher done. Let’s get into the actual patterns.
Pattern 1: Balanced / Matching Problems
This is the “gateway drug” pattern. It’s usually the first stack problem anyone solves, and honestly, it teaches you the core intuition for everything else: when something needs to be “remembered” until its matching partner shows up, a stack remembers it for you.
The classic: Valid Parentheses
function isValid(s) {
const stack = [];
const pairs = { ')': '(', ']': '[', '}': '{' };
for (const char of s) {
if (char === '(' || char === '[' || char === '{') {
stack.push(char); // opening bracket, save it for later
} else {
// closing bracket - it MUST match the top of the stack
if (stack.pop() !== pairs[char]) return false;
}
}
return stack.length === 0; // nothing left unmatched
}Think about it like a to-do list you keep flipping through. Every time you open something, you write it down. Every time you close something, you check: does this match the last thing I wrote down? If it doesn’t, something’s broken. If your list is empty at the end, everything got closed properly.
Practice these:
Valid Parentheses (Easy)
Minimum Remove to Make Valid Parentheses (Medium)
Longest Valid Parentheses (Hard)
Remove Invalid Parentheses (Hard)
Pattern 2: Monotonic Stack — The One That Actually Separates Candidates
If you remember only one pattern from this entire article, make it this one. This is the pattern that shows up disguised as “temperature,” “stock price,” “building height,” and “rainfall” problems — and every single time, it’s the same trick underneath.
A monotonic stack is just a stack that keeps its elements in increasing or decreasing order, and pops elements the moment they break that order.
Here’s the real question that finally made this click for me: why do we even need this? Because brute-forcing “find the next bigger thing to the right” for every element takes O(n²) — you’d rescan the whole array for every single element. A monotonic stack gets it done in O(n) because every element is pushed once and popped at most once. That’s it. That’s the whole efficiency trick.
Next Greater Element
function nextGreaterElement(nums) {
const result = new Array(nums.length).fill(-1);
const stack = []; // stores INDICES, not values
for (let i = 0; i < nums.length; i++) {
// while current number is bigger than whatever the stack is "waiting" on
while (stack.length && nums[stack[stack.length - 1]] < nums[i]) {
const idx = stack.pop();
result[idx] = nums[i]; // found its answer!
}
stack.push(i);
}
return result;
}
// nums = [2, 1, 3, 2, 4, 3]
// result = [3, 3, 4, 4, -1, -1]Notice we’re pushing indices, not values. This one small detail trips up so many people. Why indices? Because sometimes the answer needs distance (“how many days until it gets warmer”), not just the value itself.
Daily Temperatures — the “disguised” version
function dailyTemperatures(temperatures) {
const answer = new Array(temperatures.length).fill(0);
const stack = []; // decreasing stack of indices
for (let i = 0; i < temperatures.length; i++) {
while (stack.length && temperatures[stack[stack.length - 1]] < temperatures[i]) {
const prevIndex = stack.pop();
answer[prevIndex] = i - prevIndex; // how many days we waited
}
stack.push(i);
}
return answer;
}Same exact logic as Next Greater Element. Just phrased differently. This is exactly why I said stacks “wear disguises” — once you see the pattern, you start noticing it everywhere.
Quick side story: I once watched a candidate spend 25 minutes trying to brute-force “Largest Rectangle in Histogram” with nested loops, sweating through the whole thing, when a monotonic stack solves it cleanly in O(n). Have you ever had that moment mid-interview where you know there’s a cleaner way but can’t find it? That’s usually a sign you haven’t drilled this pattern enough yet — and that’s completely fixable.
Practice these:
Next Greater Element I & II (Easy/Medium)
Daily Temperatures (Medium)
Online Stock Span (Medium)
Largest Rectangle in Histogram (Hard)
Trapping Rain Water (Hard)
Sum of Subarray Minimums (Medium)
Pattern 3: Stack Design Tricks (Min Stack & Friends)
This pattern tests something different — not your ability to spot a pattern, but your ability to design a data structure with a constraint. The classic question: “Can you get the minimum element of a stack in O(1) time?”
The naive answer is “just scan the stack” — but that’s O(n), and the interviewer will immediately ask you to do better.
Min Stack
class MinStack {
constructor() {
this.stack = [];
this.minStack = []; // tracks the minimum "at each level"
}
push(val) {
this.stack.push(val);
// push the new minimum onto minStack too, even if it's the same as before
const currentMin = this.minStack.length
? Math.min(this.minStack[this.minStack.length - 1], val)
: val;
this.minStack.push(currentMin);
}
pop() {
this.stack.pop();
this.minStack.pop(); // keep both stacks in sync
}
top() {
return this.stack[this.stack.length - 1];
}
getMin() {
return this.minStack[this.minStack.length - 1];
}
}The trick is simple once you see it: keep a second stack that tracks “what was the minimum at this point in time.” When you pop from the main stack, pop from the min-stack too, so they always stay in sync.
Does this feel wasteful, using double the memory? A little. But O(1) time for getMin() is usually worth it, and interviewers want to see that you can trade space for time on purpose, not by accident.
Practice these:
Min Stack (Medium)
Max Stack (Hard)
Implement Queue using Stacks (Easy)
Implement Stack using Queues (Easy)
Pattern 4: Expression Evaluation
Ever wonder how a calculator app actually evaluates 3 + 4 * 2 - (1 + 5) correctly, respecting operator precedence and brackets? Stacks. That's genuinely how most calculator engines work under the hood.
Basic Calculator (handles + and — with parentheses)
function calculate(s) {
const stack = [];
let result = 0;
let number = 0;
let sign = 1;
for (let i = 0; i < s.length; i++) {
const char = s[i];
if (!isNaN(char) && char !== ' ') {
number = number * 10 + parseInt(char);
} else if (char === '+') {
result += sign * number;
number = 0;
sign = 1;
} else if (char === '-') {
result += sign * number;
number = 0;
sign = -1;
} else if (char === '(') {
// save current result and sign, start fresh for the inner expression
stack.push(result, sign);
result = 0;
sign = 1;
} else if (char === ')') {
result += sign * number;
number = 0;
result *= stack.pop(); // the sign we saved before "("
result += stack.pop(); // the result we saved before "("
}
}
return result + sign * number;
}This one genuinely takes a few tries to get comfortable with. Don’t worry if it doesn’t click on the first read — trace through a small example like "1 + (2 - 3)" on paper with an actual stack drawn out. It'll click faster than staring at the code.
Practice these:
Evaluate Reverse Polish Notation (Medium)
Basic Calculator I & II (Hard/Medium)
Decode String (Medium)
Infix to Postfix Conversion (classic GfG-style question, great for understanding operator precedence)
Pattern 5: Recursion Is Just a Hidden Stack
Here’s a fact that genuinely surprised me the first time I understood it properly: every recursive function you’ve ever written is already using a stack. It’s called the call stack, and it’s managed by the language runtime, not by you.
That’s exactly why deep recursion causes a “stack overflow” error — you’re literally filling up a stack until it runs out of space.
So what happens when an interviewer says “solve this without recursion”? You just make the stack explicit yourself.
Iterative DFS on a Binary Tree (instead of recursive)
function iterativeDFS(root) {
if (!root) return [];
const stack = [root];
const result = [];
while (stack.length) {
const node = stack.pop();
result.push(node.val);
// push right first so left gets processed first (LIFO)
if (node.right) stack.push(node.right);
if (node.left) stack.push(node.left);
}
return result;
}This is the exact same traversal as recursive DFS. We just replaced the “invisible” call stack with a stack we manage ourselves. Once you see this connection, backtracking problems and tree/graph traversal problems stop feeling like a separate topic and start feeling like an extension of stacks.
Has anyone else had that “oh wait, recursion IS a stack” moment way later than they’d like to admit? I had mine in my third year of working professionally. No shame in it — just flagging that it’s a genuinely common gap.
Pattern 6: Real-World Flavored Problems
These are the ones interviewers love because they sound like actual product features, not abstract puzzles.
Asteroid Collision — two asteroids moving toward each other, bigger one survives, equal ones both explode. Classic stack simulation:
function asteroidCollision(asteroids) {
const stack = [];
for (const asteroid of asteroids) {
let alive = true;
// only collide if current is moving left (-) and stack top is moving right (+)
while (alive && asteroid < 0 && stack.length && stack[stack.length - 1] > 0) {
const top = stack[stack.length - 1];
if (top < -asteroid) {
stack.pop(); // top asteroid destroyed
} else if (top === -asteroid) {
stack.pop(); // both destroyed
alive = false;
} else {
alive = false; // current asteroid destroyed
}
}
if (alive) stack.push(asteroid);
}
return stack;
}Simplify Path (this is literally how cd .. and cd . resolution works in file systems):
function simplifyPath(path) {
const stack = [];
const parts = path.split('/');
for (const part of parts) {
if (part === '' || part === '.') continue; // ignore empty and current-dir
if (part === '..') {
stack.pop(); // go up one directory
} else {
stack.push(part);
}
}
return '/' + stack.join('/');
}Browser “back” button history? Same stack idea — every page you visit gets pushed, hitting back pops it off. Undo/redo in a text editor? Two stacks, one for undo history, one for redo history. This pattern shows up in real products constantly, which is exactly why interviewers like asking it.
Practice these:
Asteroid Collision (Medium)
Simplify Path (Medium)
Remove Duplicate Letters (Hard)
Design Browser History (Medium)
Decode String (Medium, also fits Pattern 4)
The Mistakes I Keep Seeing (Including Ones I’ve Made Myself)
Forgetting to check if the stack is empty before peeking or popping. This causes silent bugs or crashes, and it’s the single most common issue I see in live interviews.
Pushing values when the problem actually needs indices (or the reverse). Ask yourself early: does my answer need position/distance info? If yes, push indices.
Not clarifying the comparison operator in monotonic stack problems. Should equal elements pop or stay? This genuinely changes the answer, and good interviewers will ask you this on purpose to see if you think it through.
Assuming stacks are only for “obvious” bracket problems. As you’ve seen above, they show up in scheduling, file systems, calculators, and simulations too.
Have you run into any of these mid-interview? I’d genuinely like to know which one bit you — comment below, it helps everyone reading this see they’re not alone.
Curated Practice List (Organized by Pattern)
Balanced / Matching
Valid Parentheses — Easy
Minimum Remove to Make Valid Parentheses — Medium
Longest Valid Parentheses — Hard
Monotonic Stack
Next Greater Element I — Easy
Next Greater Element II — Medium
Daily Temperatures — Medium
Online Stock Span — Medium
Sum of Subarray Minimums — Medium
Largest Rectangle in Histogram — Hard
Trapping Rain Water — Hard
Stack Design
Min Stack — Medium
Implement Queue using Stacks — Easy
Implement Stack using Queues — Easy
Max Stack — Hard
Expression Evaluation
Evaluate Reverse Polish Notation — Medium
Basic Calculator II — Medium
Basic Calculator — Hard
Decode String — Medium
Recursion / Iterative Conversion
Binary Tree Inorder Traversal (Iterative) — Medium
Flatten Binary Tree to Linked List (using stack) — Medium
Iterative DFS on Graphs — Medium
Real-World Flavored
Asteroid Collision — Medium
Simplify Path — Medium
Design Browser History — Medium
Remove Duplicate Letters — Hard
That’s roughly 24 problems. Realistically, if you solve these once on your own, then re-solve the monotonic stack ones a second time a few days later without looking at your first solution, you’ll walk into an interview recognizing this pattern within the first 30 seconds of reading the question.
My Honest Closing Thoughts
If I had to boil this entire article into one sentence, it’d be this: stacks aren’t a “topic,” they’re a lens. Once you’ve drilled these seven patterns, you stop seeing “temperature array” or “file path” problems as new challenges — you start seeing them as the same six or seven tricks wearing different costumes.
That’s genuinely the biggest shift that happens once you’ve practiced this enough. The problems don’t get easier. You just get faster at recognizing which fifteen-line trick applies.
So here’s my real question for you, and I actually want an answer in the comments: which of these seven patterns did you already know cold, and which one genuinely surprised you? I’m curious whether the monotonic stack pattern trips up as many people as I think it does, or if that’s just been my experience.
If this helped even a little, practice three problems from the list above this week. Not all 24 at once — three. Muscle memory beats cramming, every single time.
From Tech By Neha Gupta
👏 Enjoyed the article? Don’t forget to leave a clap.
💬 Have thoughts or questions? Share them in the comments.