Longest Substring Without Repeating Characters
Medium
Given a string s, find the length of the longest substring without repeating characters.
Imagine picking colored candies from a conveyor belt and putting them into your basket. You want the longest continuous streak of distinct colors. If you grab a color you already have in your basket, you don't dump the whole basket and start from scratch! You simply discard candies from the left until the duplicate color is gone, and then keep picking. The largest basket size you reached at any moment is your answer.
Reference: LeetCode #3 • Longest Substring Without Repeating Characters
Sliding Window Visualizer
Optimal: Sliding Window with Hash Map (Index Jump)Initialize Sliding Window & Map
IN PROGRESSWe initialize left = 0, maxLength = 0, and an empty hash map lastSeen. The map will remember the most recent index where each character appeared.
Initialize pointers and hash map: let left = 0; const lastSeen = new Map();Why the Optimal Solution? (Deriving the Approach)
From slow nested loops to a single-pass O(n) sliding window with direct index jumping.
Brute Force Substrings
Generate every possible substring and check if all characters are distinct using a hash set.
Throwing Away Progress
When a duplicate is found at index j, restarting at i + 1 re-verifies characters you already know are unique.
Two-Pointer Window
Expand right pointer. When a duplicate enters, slide left forward until the duplicate drops out.
Why Slide Slowly?
Advancing left one index at a time in a while loop can take up to n steps if the duplicate is deep inside.
Direct Map Jump
Store lastSeen[char] = index. Instantly jump left = max(left, lastSeen[c] + 1) in a single O(1) step!
Complexity Analysis for Optimal (Map Jump)
Each character is visited exactly once by the right pointer. Left pointer directly jumps using the hash map, never backtracking.
At most min(n, character_set_size) entries stored in the hash map (e.g. 26 lowercase English letters or 128 ASCII symbols).
Brute Force Approach
O(n²) Time
Generate all possible contiguous substrings starting at index i. For each starting point, expand an inner loop j and use a hash set to detect the first repeated character.
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;
seen.add(s[j]);
maxLength = Math.max(maxLength, j - i + 1);
}
}
Whenever a duplicate is hit at index j, the algorithm resets all the way back to i + 1. This discards all knowledge of uniqueness between i + 1 and j - 1, resulting in redundant O(n²) character comparisons.
Optimal Approach: Direct Jump Window
O(n) Time ✓
Maintain a dynamic window [left, right]. Store the most recent index of each character in a Hash Map. When a duplicate s[right] was previously seen inside the window, jump left = lastSeen[char] + 1 immediately!
for (let right = 0; right < s.length; right++) {
const char = s[right];
if (lastSeen.has(char) && lastSeen.get(char) >= left) {
left = lastSeen.get(char) + 1;
}
lastSeen.set(char, right);
maxLength = Math.max(maxLength, right - left + 1);
}
The right pointer visits each character exactly once, and left only jumps forward in O(1) time. Neither pointer ever backtracks, yielding deterministic single-pass O(n) performance.
Example Test Cases
Official LeetCode ExamplesRules & Limits
Constraints- String length up to 50,000
0 ≤ s.length ≤ 5 × 10⁴. An O(n²) approach performs ~1.25 billion operations and will Time Out (TLE). - Full ASCII character set
sconsists of English letters, digits, symbols, and spaces. - Empty string edge case
When
s = "", the output must be0. - Substrings must be contiguous
Characters must be strictly adjacent in the original string without skipping.
Key Takeaways & Interview Mental Models
Sliding Window Principles
Always maintain a clear guarantee: every character between left and right is strictly unique. If a new character violates this invariant, restore it before updating the answer.
lastSeen >= left
The hash map keeps historical positions. If a character was seen at index 2, but left is already at index 5, that previous character is outside the active window! Only jump if lastSeen[c] >= left.
Both Set-based sliding window and Map-based jumping are asymptotically linear. But index jumping reduces the number of operations from at most 2n down to exactly n, making it the gold standard in competitive programming and interviews.