LeetCode Pattern/Sliding Window/Sliding Window Intuition Explained Step-by-Step (For Beginners)

Sliding Window Intuition Explained Step-by-Step (For Beginners)

LeetCopilot Team
Nov 2, 2025
10 min read
Sliding WindowAlgorithmsBeginner GuideTwo Pointers
Struggling to understand when to shrink or expand the window? This step-by-step guide breaks down the intuition behind the Sliding Window pattern with visual examples and mental models.

If you have ever stared at a "Medium" LeetCode problem involving arrays or strings and felt like you needed a nested loop, you are not alone. The brute force approach is natural. But it is also slow—usually .

The Sliding Window pattern is the technique that transforms that slow brute force into a blazing fast solution. It is not just an algorithm; it is a way of thinking about data as a fluid stream rather than a static block.

In this guide, we will build your sliding window intuition from the ground up. You will learn the difference between fixed and dynamic windows, master the "grow until invalid, then shrink" mental model, and walk through real examples step-by-step.

TL;DR — The Sliding Window Algorithm:

  1. Initialize left = 0.
  2. Loop right from 0 to n.
  3. Add nums[right] to window.
  4. while window is invalid: remove nums[left], increment left.
  5. Update max/min result.

What is sliding window?

At its core, a Sliding Window is a sub-list that runs over an underlying collection. Instead of re-calculating the entire subarray every time we move one step, we reuse the result from the previous step.

Think of it like a window frame sliding over a long strip of paper. You can only see a portion of the paper at a time. As you slide the frame to the right, one new character enters the view, and one old character leaves.

This technique is a specific variation of the Two Pointers pattern, where both pointers move in the same direction to define a range [left, right].

Fixed‐size vs dynamic window: visual comparison

There are two distinct flavors of this pattern, and mixing them up is a common source of bugs.

1. Fixed-Size Window

The window size never changes. You slide it one element at a time.

  • Use case: "Find the maximum sum of any contiguous subarray of size 3."
  • Movement: right increments by 1, left increments by 1. They are locked together.

2. Dynamic-Size Window

The window grows and shrinks like a caterpillar based on a condition.

  • Use case: "Find the longest substring without repeating characters."
  • Movement: right increments to grow. left increments only when the window becomes invalid (to shrink it).

This guide focuses on the Dynamic Window, as it is the one that trips up most candidates.

Walkthrough Example #1: Longest Substring Without Repeating Characters

Let's solve the classic problem: Given string s = "abcabcbb", find the length of the longest substring without repeating characters.

We use a Hash Set to track characters in our current window.

Step 1: Expand the right pointer

We start with left = 0 and right = 0.
We move right forward, adding characters to our set.

  • Add 'a'. Window: "a". Valid.
  • Add 'b'. Window: "ab". Valid.
  • Add 'c'. Window: "abc". Valid.

Step 2: Shrink the left pointer

Now right points to the second 'a'.

  • We try to add 'a'. Duplicate found! The window "abca" is invalid.

This is the crucial moment. We cannot expand further. We must shrink from the left until the window is valid again.

  • Remove s[left] ('a') from the set.
  • Increment left.
  • New Window: "bca". Valid? Yes.

Now we can resume expanding right.

function lengthOfLongestSubstring(s: string): number {
    let left = 0;
    let maxLength = 0;
    const charSet = new Set<string>();

    for (let right = 0; right < s.length; right++) {
        // Shrink the window if adding s[right] creates a duplicate
        while (charSet.has(s[right])) {
            charSet.delete(s[left]);
            left++;
        }
        // Expand the window
        charSet.add(s[right]);
        maxLength = Math.max(maxLength, right - left + 1);
    }
    return maxLength;
}
typescript

Walkthrough Example #2: Subarray Sum ≤ K

Let's look at a slightly different constraint: "Find the length of the longest subarray with sum ." (Assume positive numbers).

  • Expand: Add numbers to currentSum.
  • Condition: Is currentSum > K?
  • Shrink: If yes, subtract nums[left] and move left forward until currentSum <= K.

Notice the pattern? The logic is identical. The only thing that changes is the condition for shrinking.

Key mental model: “grow until invalid, then shrink”

If you remember only one thing from this article, make it this loop:

  1. Grow: Increase right to include a new element.
  2. Check: Does adding this element break the rule? (e.g., duplicate char, sum too large).
  3. Shrink: If the rule is broken, increase left to remove elements until the rule is satisfied again.
  4. Update: Update your global maximum (or minimum) with the current valid window size.

This "caterpillar" movement ensures we check every possible valid window without redundant checks.

Warning: This logic relies on the problem being "monotonic." If adding an element doesn't consistently increase the "cost", this breaks. See our guide on When NOT to Use Sliding Window for those edge cases.

Common misconceptions

Misconception 1: "The window only grows."

Beginners often forget the while loop for shrinking. They use an if statement instead.

  • Correction: You might need to remove multiple elements from the left to make the window valid again. Always use while.

Misconception 2: "We shrink first."

Usually, we expand first to see if we can make a bigger window. We only shrink when forced to.

  • Correction: The standard template is for (right) { expand; while (invalid) shrink; update; }.

Tips for building intuition

  1. Use your hands: Literally use your index fingers as pointers on a piece of paper. Move the right one. When you hit a "bad" state, move the left one.
  2. Dry run with a table: Write columns for left, right, window_content, and condition_value. Fill it out row by row.
  3. Practice with Visualizers: Tools like LeetCopilot's Study Mode can help you visualize these patterns interactively, highlighting exactly when the window shifts.

FAQ

Q: Why is this O(N) if there is a loop inside a loop?
A: Great observation. Although there is a while loop inside the for loop, the left pointer only moves forward. It never moves back. In the worst case, left visits each element once and right visits each element once. Total operations = , which is .

Q: How do I know if it's a sliding window problem?
A: Look for keywords like "longest", "shortest", "contiguous subarray", or "substring". If the problem asks for a range that satisfies a condition, it's a strong candidate.

Q: Does this work for "Subarray Sum Equals K"?
A: No! If the array has negative numbers, the "grow until invalid" logic fails. You need Prefix Sums for that.

Summary and where to go next

Sliding Window is about managing a dynamic range. It is efficient because it avoids re-doing work. By mastering the expansion and shrinking logic, you can solve dozens of "Medium" and "Hard" string/array problems.

Next Steps:

  1. Read When NOT to Use Sliding Window to avoid common traps.
  2. Practice "Longest Substring Without Repeating Characters" on LeetCode.
  3. Try "Minimum Size Subarray Sum" to practice the "shortest" window variant.
  4. Check out our Sliding Window Template for Strings for a deep dive into string problems.

Ready to Practice This Pattern?

Apply this pattern with LeetCopilot's AI-powered hints, notes, and mock interviews. Transform your coding interview preparation today.

Related Tutorials