Stack Fundamentals

Loading concept...

πŸ₯ž Stacks: Your Magical Plate Tower


The Story of the Pancake Stack

Imagine you’re at a breakfast buffet. The chef keeps adding fresh, hot pancakes to a pile. When you want one, you always take from the top β€” never from the middle or bottom!

This is exactly how a Stack works in programming. It’s a special container where:

  • You add items on top (called push)
  • You remove items from the top (called pop)
  • You can only see the top item (called peek)

🎯 One Rule: Last In, First Out (LIFO) The last pancake added is the first one you eat!


Stack Fundamentals

What Makes a Stack Special?

Think of stacking your favorite books. You put one book on top of another. When you want a book, you take the one on top first.

// Creating a stack in JavaScript
const stack = [];

// Push: Add to top
stack.push("Book 1");
stack.push("Book 2");
stack.push("Book 3");
// Stack now: [Book1, Book2, Book3]
//                          ↑ top

// Pop: Remove from top
const topBook = stack.pop();
// topBook = "Book 3"
// Stack now: [Book1, Book2]

// Peek: Look at top (without removing)
const peekBook = stack[stack.length - 1];
// peekBook = "Book 2"

Key Operations

Operation What It Does Time
push() Add to top O(1)
pop() Remove from top O(1)
peek() View top O(1)
isEmpty() Check if empty O(1)

πŸ”— Balanced Parentheses

The Matching Game

Imagine you have a box of colored brackets: (), [], {}. Your job is to check if every opening bracket has its matching closing bracket β€” and in the right order!

Example:

  • "([])" βœ… Valid β€” each opener finds its partner
  • "([)]" ❌ Invalid β€” brackets crossed paths

How Stack Solves This

graph TD A["Read #40;"] --> B["Push #40; to stack"] B --> C["Read ["] C --> D["Push [ to stack"] D --> E["Read ]"] E --> F["Pop [ β€” Match!"] F --> G["Read #41;"] G --> H["Pop #40; β€” Match!"] H --> I["Stack empty = Valid!"]

The Code

function isBalanced(str) {
  const stack = [];
  const pairs = {
    ')': '(',
    ']': '[',
    '}': '{'
  };

  for (const char of str) {
    if (char === '(' ||
        char === '[' ||
        char === '{') {
      stack.push(char);
    }
    else if (pairs[char]) {
      if (stack.pop() !== pairs[char]) {
        return false;
      }
    }
  }

  return stack.length === 0;
}

// Examples
isBalanced("()[]{}");  // true
isBalanced("([])");    // true
isBalanced("([)]");    // false
isBalanced("((");      // false

Why It Works

  • Opening bracket? Push it on the stack
  • Closing bracket? Pop and check if it matches
  • End of string? Stack should be empty

πŸ“ Simplify Path

The GPS Navigator Problem

You’re giving directions in a file system. People write messy paths like:

  • "/home//user/../documents/./photos"

You need to clean it up to:

  • "/home/documents/photos"

The Rules

Symbol Meaning
/ Separator
. Current folder (ignore)
.. Go back one folder
// Same as /

Stack to the Rescue!

graph TD A["Split path by /"] --> B["For each part"] B --> C{What is it?} C -->|Empty or .| D["Skip it"] C -->|..| E["Pop stack"] C -->|folder name| F["Push to stack"] D --> B E --> B F --> B B --> G["Join with /"]

The Code

function simplifyPath(path) {
  const stack = [];
  const parts = path.split('/');

  for (const part of parts) {
    if (part === '' || part === '.') {
      continue; // Skip empty and current
    }
    else if (part === '..') {
      stack.pop(); // Go back one level
    }
    else {
      stack.push(part); // Add folder
    }
  }

  return '/' + stack.join('/');
}

// Examples
simplifyPath("/home/");
// β†’ "/home"

simplifyPath("/../");
// β†’ "/"

simplifyPath("/home//foo/");
// β†’ "/home/foo"

simplifyPath("/a/./b/../../c/");
// β†’ "/c"

πŸ† Longest Valid Parentheses

The Treasure Hunt

Given a string of only ( and ), find the longest stretch where all parentheses are perfectly balanced.

Example:

  • "(()" β†’ Answer: 2 (the () at the end)
  • ")()())" β†’ Answer: 4 (the ()() in middle)

The Stack Strategy

We use the stack to store positions (indices), not the characters themselves!

graph TD A["Start: Push -1 as base"] --> B["Read each character"] B --> C{Is it #40; ?} C -->|Yes| D["Push its index"] C -->|No| E["Pop stack"] E --> F{Stack empty?} F -->|Yes| G["Push current index"] F -->|No| H["Calculate length"] H --> I["Update max length"] D --> B G --> B I --> B

The Code

function longestValidParens(s) {
  const stack = [-1]; // Base index
  let maxLen = 0;

  for (let i = 0; i < s.length; i++) {
    if (s[i] === '(') {
      stack.push(i);
    } else {
      stack.pop();

      if (stack.length === 0) {
        stack.push(i); // New base
      } else {
        const len = i - stack[stack.length - 1];
        maxLen = Math.max(maxLen, len);
      }
    }
  }

  return maxLen;
}

// Examples
longestValidParens("(()");    // 2
longestValidParens(")()())"); // 4
longestValidParens("()(()");  // 2

Why Push -1?

The -1 acts as a β€œfloor” so when we calculate length, we always have something to subtract from!


🧹 Remove Invalid Parentheses

The Cleanup Crew

Given a string with letters and parentheses, remove the minimum number of invalid parentheses to make it valid.

Example:

  • "()())()" β†’ ["()()()", "(())()"]
  • "(a)())()" β†’ ["(a)()()", "(a())()"]

The Two-Pass Approach

graph TD A["Pass 1: Left to Right"] --> B["Remove extra #41;"] B --> C["Pass 2: Right to Left"] C --> D["Remove extra #40;"] D --> E["Collect all valid results"]

The Code

function removeInvalidParens(s) {
  const results = new Set();

  function remove(str, start,
                  open, close, rev) {
    let count = 0;

    for (let i = start; i < str.length; i++) {
      if (str[i] === open) count++;
      if (str[i] === close) count--;

      if (count < 0) {
        // Remove one close bracket
        for (let j = 0; j <= i; j++) {
          if (str[j] === close) {
            // Skip duplicates
            if (j === 0 ||
                str[j-1] !== close) {
              const newStr =
                str.slice(0, j) +
                str.slice(j + 1);
              remove(newStr, i,
                     open, close, rev);
            }
          }
        }
        return;
      }
    }

    // Reverse and check other direction
    const reversed = str.split('')
                        .reverse()
                        .join('');
    if (rev) {
      results.add(reversed);
    } else {
      remove(reversed, 0, ')', '(', true);
    }
  }

  remove(s, 0, '(', ')', false);
  return [...results];
}

Key Insight

  • First pass: Fix extra ) by going left-to-right
  • Second pass: Fix extra ( by reversing and repeating!

βž• Minimum Add to Make Valid

The Missing Pieces

Count how many parentheses you need to add to make a string valid.

Example:

  • "())" β†’ Add 1 ( at start
  • "(((" β†’ Add 3 ) at end
  • "()))((" β†’ Add 4 total

The Simple Counter Method

graph TD A["Two counters: open, close"] --> B["Read each char"] B --> C{Is it #40; ?} C -->|Yes| D["open++"] C -->|No| E{open > 0?} E -->|Yes| F["open-- #40;matched!#41;"] E -->|No| G["close++ #40;unmatched#41;"] D --> B F --> B G --> B B --> H["Answer = open + close"]

The Code

function minAddToMakeValid(s) {
  let open = 0;   // Unmatched (
  let close = 0;  // Unmatched )

  for (const char of s) {
    if (char === '(') {
      open++;
    }
    else if (char === ')') {
      if (open > 0) {
        open--; // Found a match!
      } else {
        close++; // No ( to match
      }
    }
  }

  return open + close;
}

// Examples
minAddToMakeValid("())");    // 1
minAddToMakeValid("(((");    // 3
minAddToMakeValid("()");     // 0
minAddToMakeValid("()))(("); // 4

Why It Works

  • open tracks unmatched (
  • close tracks unmatched )
  • The sum is what we need to add!

🎯 Quick Summary

Problem Strategy Key Idea
Balanced Parens Push/Pop matching Match each closer with opener
Simplify Path Stack of folders .. pops, names push
Longest Valid Stack of indices Calculate spans
Remove Invalid Two-pass BFS Remove extras carefully
Min Add Two counters Track unmatched both ways

πŸš€ You Did It!

You now understand how stacks power some of the most common string problems in programming. Remember:

πŸ₯ž Stack = Pancake Tower Last pancake in, first pancake out!

Every time you see parentheses, brackets, or β€œundo” functionality β€” think Stack!

Loading story...

No Story Available

This concept doesn't have a story yet.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

Interactive Preview

Interactive - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Interactive Content

This concept doesn't have interactive content yet.

Cheatsheet Preview

Cheatsheet - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Cheatsheet Available

This concept doesn't have a cheatsheet yet.

Quiz Preview

Quiz - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Quiz Available

This concept doesn't have a quiz yet.