LeetCopilot Logo
LeetCopilot
LeetCode Pattern/Sliding Window/6 Sliding Window Bugs That Break Your Solution (With Fixes)

6 Sliding Window Bugs That Break Your Solution (With Fixes)

LeetCopilot Team
Nov 17, 2025
16 min read
Sliding WindowDebuggingLeetCodeCommon MistakesInterview Prep
Using 'if' instead of 'while'? Calculating size as 'right - left'? These 6 mistakes trip up 90% of candidates. Here's the debugging checklist that catches them all.

You've read the pattern guides. You've solved 20 LeetCode problems. You know sliding window.

Then you're in an interview, and your solution fails on test case 47. Or worse—it passes locally but times out on submission. You stare at your code, muttering "but I used two pointers..."

Here's the truth: knowing the pattern is only half the battle. The other half is avoiding the landmines that turn a conceptually correct solution into a buggy mess.

In this guide, I'll walk you through the 6 most common sliding window mistakes I've seen in code reviews and interviews, complete with:

  • Real examples of broken code
  • Why the mistake happens
  • How to fix it (and how templates prevent it)
  • A debugging checklist you can memorize

By the end, you'll code defensively and catch bugs before they cost you the interview.

TL;DR — 6 Deadly Sliding Window Mistakes

  1. Mis-identifying the pattern: Using sliding window for sum-equals-K with negatives (use prefix sums instead)
  2. Off-by-one errors: Calculating window size as right - left instead of right - left + 1
  3. Missing shrink logic: Forgetting the while loop to shrink until valid
  4. Ignoring edge cases: Empty input, single element, zeros, negative numbers
  5. Poor invariant definition: Shrinking at the wrong time or using wrong condition
  6. Performance traps: Nested loops making it instead of

Fix: Use the standard template to avoid 90% of these bugs.

Mis-identifying the Problem Pattern

This is the meta-mistake: using sliding window when you shouldn't.

Using Sliding Window When Prefix Sum/DP is Needed

The Scenario: You see "subarray sum" and immediately think "sliding window!"

But then you notice: the array has negative numbers, or the problem asks for "number of subarrays with sum exactly K."

Why It Fails: Sliding window requires monotonicity. Negative numbers break this. When you expand the window and the sum decreases, you can't make a greedy decision about whether to shrink or expand.

Example Error:

python
# WRONG: Trying to find subarrays with sum = k using sliding window
def subarraySum(nums: List[int], k: int) -> int:
    left = 0
    current_sum = 0
    count = 0
    
    for right in range(len(nums)):
        current_sum += nums[right]
        
        # This logic is broken with negative numbers
        while current_sum > k and left <= right:
            current_sum -= nums[left]
            left += 1
        
        if current_sum == k:
            count += 1
    
    return count

# Test case that breaks it:
nums = [1, -1, 1, -1, 1]
k = 0
# Expected: 4 (indices [0,1], [1,2], [2,3], [3,4])
# Your code returns: 1 (only finds [0,1])

Why This Happens: After adding nums[right] = -1, the sum decreases even though we expanded. The while loop doesn't know whether to keep shrinking or wait for more elements.

The Fix: Use Prefix Sum + Hash Map

For "subarray sum equals K" with any numbers (including negatives), use this pattern:

python
def subarraySum(nums: List[int], k: int) -> int:
    prefix_sum = 0
    count = 0
    sum_count = {0: 1}  # Handle subarrays starting at index 0
    
    for num in nums:
        prefix_sum += num
        
        # If (prefix_sum - k) exists, we found a subarray
        if prefix_sum - k in sum_count:
            count += sum_count[prefix_sum - k]
        
        sum_count[prefix_sum] = sum_count.get(prefix_sum, 0) + 1
    
    return count

Decision Rule: If the problem involves:

  • Exact sum with unrestricted values → Prefix sum
  • "At most/at least" constraint with non-negative values → Sliding window
  • Non-contiguous elements (subsequences) → DP

Pattern Recognition Tip: Check the constraints. If - 10 ^ 4 <= nums[i] <= 10 ^ 4, that's a red flag for sliding window on sums. Learn more about when NOT to use sliding window and why negative numbers break monotonicity.

Shrinking/Expanding Logic Mistakes

Even when sliding window is the right choice, implementation bugs are common.

Off-by-One: The Window Size Error

The Mistake: Calculating window size as right - left instead of right - left + 1.

Example:

javascript
// WRONG
function maxSubArray(nums, k) {
    let left = 0, maxLen = 0;
    
    for (let right = 0; right < nums.length; right++) {
        // ... window logic ...
        
        maxLen = Math.max(maxLen, right - left);  // BUG!
    }
    return maxLen;
}

// When left = 0, right = 2, window contains indices [0,1,2] = 3 elements
// But right - left = 2 - 0 = 2 ❌
// Correct: right - left + 1 = 2 - 0 + 1 = 3 ✓

Why This Happens: Confusion between "index distance" and "element count." Array indices are 0-based, but element count starts at 1.

The Fix: Always use right - left + 1. Memorize it as part of your sliding window template. This is also covered in our guide on off-by-one errors.

Missing Shrink Condition: The Infinite Loop

The Mistake: Not shrinking when the window becomes invalid.

Example:

python
# WRONG: Finding longest substring with at most k distinct characters
def lengthOfLongestSubstringKDistinct(s: str, k: int) -> int:
    left = 0
    char_count = {}
    max_len = 0
    
    for right in range(len(s)):
        char_count[s[right]] = char_count.get(s[right], 0) + 1
        
        # MISSING: while len(char_count) > k: ...
        
        max_len = max(max_len, right - left + 1)
    
    return max_len

# This always returns len(s), ignoring k entirely!

The Fix: Always include the shrink loop for variable-size windows:

python
# CORRECT
def lengthOfLongestSubstringKDistinct(s: str, k: int) -> int:
    left = 0
    char_count = {}
    max_len = 0
    
    for right in range(len(s)):
        char_count[s[right]] = char_count.get(s[right], 0) + 1
        
        # Shrink until valid
        while len(char_count) > k:
            char_count[s[left]] -= 1
            if char_count[s[left]] == 0:
                del char_count[s[left]]
            left += 1
        
        max_len = max(max_len, right - left + 1)
    
    return max_len

Code Snippet: Wrong vs Correct Shrink

Wrong PatternCorrect Pattern
if window_invalid(): while window_invalid():
left += 1 (without removing state)Remove state, then left += 1
Checking validity before expandingExpand, then shrink if invalid

Key Insight: The shrink loop is while, not if. You may need to shrink multiple times to restore validity.

Ignoring Edge Cases

Edge cases are where most "correct" solutions fail in interviews.

Negative Numbers, Zeros, Empty Input

Common Edge Cases:

  1. Empty input: s = "" or nums = []
  2. Single element: s = "a"
  3. All identical elements: nums = [5, 5, 5, 5]
  4. Zeros: nums = [0, 0, 1, 2] (for product problems, this breaks naive multiplication)
  5. Negative numbers: Already covered for sums; also breaks product problems

Example Failure with Zeros:

java
// WRONG: Maximum product subarray
public int maxProduct(int[] nums) {
    int result = nums[0];
    int currentProduct = 1;
    
    for (int num : nums) {
        currentProduct *= num;  // If num = 0, product becomes 0 forever!
        result = Math.max(result, currentProduct);
    }
    return result;
}

// Input: [2, 3, -2, 4]
// Expected: 6 (subarray [2,3])
// Your code: 0 (because -2 * 4 makes it negative, then stays negative)

The Fix: Reset state when encountering zeros or negative numbers:

java
public int maxProduct(int[] nums) {
    int maxSoFar = nums[0];
    int maxEndingHere = 1;
    int minEndingHere = 1;
    
    for (int num : nums) {
        if (num < 0) {
            // Swap max and min because multiplying by negative flips sign
            int temp = maxEndingHere;
            maxEndingHere = minEndingHere;
            minEndingHere = temp;
        }
        
        maxEndingHere = Math.max(num, maxEndingHere * num);
        minEndingHere = Math.min(num, minEndingHere * num);
        
        maxSoFar = Math.max(maxSoFar, maxEndingHere);
    }
    return maxSoFar;
}

Edge Case Checklist:

  • ✅ Test with empty input
  • ✅ Test with single element
  • ✅ Test with all elements the same
  • ✅ Test with zeros (for product/division)
  • ✅ Test with extreme values (INT_MAX, INT_MIN)

Poor Invariant Definition

An "invariant" is a condition that's always true at a specific point in your loop. Poor invariants lead to subtle bugs.

Defining the Window Validity Incorrectly

The Problem: You define "valid window" in a way that doesn't match the problem constraints.

Example: "Find the longest substring with at most 2 distinct characters."

WRONG invariant: "The window has exactly 2 distinct characters."
RIGHT invariant: "The window has at most 2 distinct characters."

Why It Matters: With the wrong invariant, you'll shrink too early:

python
# WRONG: Shrinks even when valid
while len(char_count) != 2:  # Should be > 2, not != 2
    # ...

This incorrectly shrinks windows with 1 distinct character, even though they're valid.

How to Fix: Write Down Your Invariant

Before coding, write a comment:

python
def lengthOfLongestSubstringTwoDistinct(s: str) -> int:
    # INVARIANT: After the while loop, the window [left, right] 
    # contains at most 2 distinct characters
    
    left = 0
    char_count = {}
    max_len = 0
    
    for right in range(len(s)):
        char_count[s[right]] = char_count.get(s[right], 0) + 1
        
        # Restore invariant
        while len(char_count) > 2:
            char_count[s[left]] -= 1
            if char_count[s[left]] == 0:
                del char_count[s[left]]
            left += 1
        
        # Now invariant holds: window is valid
        max_len = max(max_len, right - left + 1)
    
    return max_len

Debugging Tip: If your code is failing mysteriously, print the window state and check if your invariant actually holds after the shrink loop.

Performance/Memory Traps

Even with correct logic, you can still fail on time/space limits.

Using Nested Loops: The O(N^2) Trap

The Mistake: Adding an inner loop that scans the entire window.

Example:

java
// WRONG: O(N^2) instead of O(N)
public int lengthOfLongestSubstring(String s) {
    int left = 0, maxLen = 0;
    
    for (int right = 0; right < s.length(); right++) {
        // Check if s[right] is duplicate
        for (int i = left; i < right; i++) {  // BUG: O(N) scan!
            if (s.charAt(i) == s.charAt(right)) {
                left = i + 1;
                break;
            }
        }
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}

Why This Fails: The inner loop makes it . For , this times out.

The Fix: Use a Set or Map for lookups:

java
public int lengthOfLongestSubstring(String s) {
    Set<Character> seen = new HashSet<>();
    int left = 0, maxLen = 0;
    
    for (int right = 0; right < s.length(); right++) {
        while (seen.contains(s.charAt(right))) {
            seen.remove(s.charAt(left));
            left++;
        }
        seen.add(s.charAt(right));
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}

Forgetting to Update Window State

The Mistake: Adding elements to the window but not removing them when shrinking.

Example:

javascript
// WRONG: Memory leak—map grows without bound
function lengthOfLongestSubstring(s) {
    let left = 0, maxLen = 0;
    const charIndex = new Map();
    
    for (let right = 0; right < s.length; right++) {
        charIndex.set(s[right], right);
        
        while (/* some condition */) {
            left++;
            // BUG: Not removing s[left-1] from charIndex!
        }
        
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}

The Fix: Always mirror your state updates:

  • When you add to the window → update state
  • When you shrink from the window → update state
javascript
// CORRECT
function lengthOfLongestSubstring(s) {
    let left = 0, maxLen = 0;
    const charSet = new Set();
    
    for (let right = 0; right < s.length; right++) {
        while (charSet.has(s[right])) {
            charSet.delete(s[left]);  // Remove from state
            left++;
        }
        charSet.add(s[right]);  // Add to state
        maxLen = Math.max(maxLen, right - left + 1);
    }
    return maxLen;
}

Takeaways & Checklist

Pre-Coding Checklist

Before writing any sliding window solution:

  1. Is this really sliding window?

    • ✅ Contiguous elements (subarray/substring)
    • ✅ Monotonic constraint (not sum-equals-K with negatives)
    • ✅ Efficient state updates possible
  2. Fixed or variable size?

    • Fixed → Simple slide (add one, remove one)
    • Variable → Expand in for, shrink in while
  3. What's my invariant?

    • Write it down: "After shrinking, the window is [definition of valid]"
  4. What state do I track?

    • Sum → int
    • Unique elements → Set
    • Frequency → Map
    • Max/min → Monotonic deque

Debugging Checklist

If your solution fails:

  1. Check window size calculation: right - left + 1, not right - left
  2. Verify shrink loop exists: while, not if
  3. Print window state: Log [left, right] and your data structure
  4. Test edge cases: Empty, single element, all same
  5. Check time complexity: Are you scanning the window inside the loop? ( bug)
  6. Verify state mirroring: Every add when expanding should have a remove when shrinking

When to Use Templates

If you're making these mistakes repeatedly, stop freestyling and use a template. Templates enforce:

  • Correct loop structure
  • Invariant maintenance
  • State update symmetry

FAQ

Q: How do I debug a sliding window solution that's failing on a specific test case?
A: Add print statements inside your loop to track left, right, window contents, and your validity condition. The bug is usually: (1) wrong shrink condition, (2) missing state update, or (3) off-by-one in size calculation.

Q: My solution works for most cases but fails on large inputs. What's wrong?
A: Likely a time complexity issue. Check if you have an scan inside your main loop (making it ). Use a Set or Map for lookups.

Q: I keep getting "index out of bounds" errors. Why?
A: You're probably accessing arr[right] or arr[left] outside the loop bounds. Make sure:

  • right never exceeds len(arr) - 1 (use for right in range(len(arr)))
  • left doesn't exceed right (add while left <= right guard)

Q: Should I always use a HashMap for sliding window?
A: No. Use the simplest data structure that works:

  • Sum → single int
  • Unique elements → Set
  • Frequency tracking → Map
  • Max/min → Deque (for advanced problems)

Q: What's the difference between if and while for shrinking?
A: Use while. A single shrink might not restore validity. Example: window has 5 distinct chars, k = 2. You need to shrink multiple times, not just once.

Q: How can I avoid these mistakes in a real interview?
A: Use LeetCopilot's Study Mode to practice with instant feedback. It catches these bugs as you code and explains why they're wrong—like having a senior engineer pair programming with you.

Want to Practice LeetCode Smarter?

LeetCopilot is a free browser extension that enhances your LeetCode practice with AI-powered hints, personalized study notes, and realistic mock interviews — all designed to accelerate your coding interview preparation.

Also compatible with Edge, Brave, and Opera

Related Tutorials