DEV Community

Timevolt
Timevolt

Posted on

From brute force to optimal: Level up your solutions like a Jedi Master

The Quest Begins (The “Why”)

Ever felt like you’re stuck grinding away at a problem that should be simple, but your code just keeps crawling? I’ve been there. A few weeks ago I was tackling a classic interview question: “Given a string, find the length of the longest substring without repeating characters.” My first instinct? Throw two nested loops at it, check every possible substring, and call it a day.

I opened my editor, typed out the brute‑force solution, ran it on a modest input like "abcabcbb" and got the right answer—3. Feeling smug, I cranked up the size to a 10‑character random string. Still fine. Then I tried a 10 000‑character string filled with random letters. My laptop started sounding like a jet engine, the runtime crept past a second, and I realized I was basically trying to boil the ocean with a teaspoon.

That moment hit me like a plot twist in a movie: I was solving the right problem, but I was using the wrong weapon. I needed a mental shift, not just more lines of code.

The Revelation (The Insight)

The breakthrough came when I stopped thinking about enumerating substrings and started asking: What do I actually need to know while I scan the string once?

If I keep a sliding window [left, right) that always contains unique characters, I can expand right as far as possible. The moment I see a duplicate, I don’t have to restart from scratch—I just need to move left just past the previous occurrence of that character.

In other words, the answer lives in the distance between two equal characters, not in rebuilding the whole window each time. This is the classic “two‑pointer” or “sliding window” trick, and it turns an O(n²) nightmare into an O(n) victory.

The “aha!” felt like discovering the cheat code in Contra—suddenly you’re invincible, and the game (or the problem) becomes a breeze.

Wielding the Power (Code & Examples)

The brute‑force attempt (the struggle)

function longestSubstringBrute(s) {
  let maxLen = 0;
  for (let i = 0; i < s.length; i++) {
    const seen = new Set();
    for (let j = i; j < s.length; j++) {
      if (seen.has(s[j])) break;      // duplicate found
      seen.add(s[j]);
      maxLen = Math.max(maxLen, j - i + 1);
    }
  }
  return maxLen;
}
Enter fullscreen mode Exit fullscreen mode

What’s wrong here?

  • The outer loop picks a start index i.
  • The inner loop scans forward until a duplicate appears, then breaks and starts the whole process again from the next i.
  • We’re re‑checking characters we’ve already seen many times → O(n²) time, O(k) space (where k is the size of the current window).

The optimal sliding‑window solution (the victory)

function longestSubstringOptimal(s) {
  const lastIndex = new Map(); // char → most recent position
  let left = 0;                // start of the current window
  let maxLen = 0;

  for (let right = 0; right < s.length; right++) {
    const ch = s[right];

    // If ch was seen inside the current window, jump left past it
    if (lastIndex.has(ch) && lastIndex.get(ch) >= left) {
      left = lastIndex.get(ch) + 1;
    }

    // Update the most recent position of ch
    lastIndex.set(ch, right);

    // Window size is right - left + 1
    maxLen = Math.max(maxLen, right - left + 1);
  }

  return maxLen;
}
Enter fullscreen mode Exit fullscreen mode

Why this works:

  • lastIndex remembers where each character last appeared.
  • When we encounter a character that’s already in the window (lastIndex.get(ch) >= left), we slide left just after its previous occurrence—no need to clear the set or restart.
  • Each character is visited at most twice (once by right, once potentially by moving left), giving linear time.
  • Space is O(min(n, charset)) – essentially the size of the character set we’re dealing with.

Common traps to avoid

Trap What it looks like Why it hurts
Resetting the whole window on a duplicate (left = right; seen.clear()) Throws away useful information and re‑scans characters already processed. Turns the algorithm back into O(n²).
Forgetting to update lastIndex after moving left Leaves stale positions, causing the window to shrink incorrectly. May miss longer valid substrings or produce wrong answers.
Using an array of size 256 for Unicode strings Works only for ASCII; breaks with emojis or non‑Latin scripts. Gives incorrect results or runtime errors on broader inputs.

Quick sanity check

console.log(longestSubstringOptimal("abcabcbb")); // 3 ("abc")
console.log(longestSubstringOptimal("bbbbb"));    // 1 ("b")
console.log(longestSubstringOptimal("pwwkew"));   // 3 ("wke")
Enter fullscreen mode Exit fullscreen mode

All match the brute‑force results, but the optimal version runs in a flash even on a 1 million‑character string.

Why This New Power Matters

Mastering the sliding‑window mindset does more than solve one interview puzzle—it rewires how you approach any problem that involves contiguous segments, subarrays, or substrings.

  • Maximum subarray sum (Kadane’s algorithm) becomes a natural extension: keep a running sum and reset when it hurts you.
  • Minimum size subarray with sum ≥ k: two pointers, expand until condition met, then shrink from the left.
  • Longest repeating character replacement (LeetCode 424): track counts inside the window and shrink when you exceed allowed changes.

Once you internalize the idea of “maintaining a valid invariant while you slide a window,” you start spotting it everywhere—from string processing to time‑series analysis, from game development (think hit‑detection zones) to data pipelines (windowed aggregations).

The best part? The code stays short, readable, and easy to test. No more nested loops that make your future self want to hide under a desk.

Your Turn

Pick a problem you’ve solved with brute force before—maybe “count the number of subarrays with sum equals k” or “find the minimum window substring.” Try to reframe it: What invariant can I keep while I move a pointer? Write the sliding‑window version, run it on a large test case, and feel that rush of invincibility.

What’s the next dragon you’ll slay with this new mental sword? Drop your story in the comments—I’d love to hear how you leveled up! 🚀

Top comments (0)