3 - Longest Substring Without Repeating Characters
Difficulty: Medium | Pattern: Sliding Window | Company tags: Amazon, Google, Facebook, Microsoft
Problem Statement
Given a string s, find the length of the longest substring without repeating characters.
Example 1:
Input: s = "abcabcbb"
Output: 3 ("abc")
Example 2:
Input: s = "bbbbb"
Output: 1 ("b")
Example 3:
Input: s = "pwwkew"
Output: 3 ("wke")
Algorithm Flow
Solution: Sliding Window + HashMap — O(n), O(min(m,n))
Key insight: Use a sliding window [left, right]. Track the last seen index of each character. When a duplicate is found, move left to just past the last occurrence.
def lengthOfLongestSubstring(s: str) -> int:
last_seen = {}
left = 0
max_len = 0
for right, c in enumerate(s):
if c in last_seen and last_seen[c] >= left:
left = last_seen[c] + 1
last_seen[c] = right
max_len = max(max_len, right - left + 1)
return max_len
Dry Run
s = "abcabcbb"
| right | c | left | max_len | action |
|---|---|---|---|---|
| 0 | a | 0 | 1 | no dup |
| 1 | b | 0 | 2 | no dup |
| 2 | c | 0 | 3 | no dup |
| 3 | a | 1 | 3 | a seen at 0 → left=1 |
| 4 | b | 2 | 3 | b seen at 1 → left=2 |
| 5 | c | 3 | 3 | c seen at 2 → left=3 |
| 6 | b | 5 | 3 | b seen at 4 → left=5 |
| 7 | b | 7 | 3 | b seen at 6 → left=7 |
Result: 3 ✓
Edge Cases
- Empty string → 0
- All same characters → 1
- All distinct → n
Complexity
- Time: O(n) — each character processed once
- Space: O(min(m,n)) where m is charset size (26 or 128)
Key Terms
| Term | Definition |
|---|---|
| Sliding window | A contiguous range [left, right] over the string that expands and contracts while a validity condition holds. |
| Window invariant | The condition "no repeated character inside [left, right]" that must always hold true. |
| Last-seen index map | A hash map from character to its most recent index, used to detect and jump past duplicates in O(1). |
| Two-pointer technique | Using two indices (left, right) that both move forward, giving an amortized O(n) traversal. |
FAQ
Q: Why do we check last_seen[c] >= left instead of just c in last_seen?
A: A character may have been seen before but already fall outside the current window (to the left of left). Without the >= left check, left could incorrectly move backward.
Q: Can this be solved without extra space? A: Not in true O(1) space for arbitrary Unicode input, but for a bounded alphabet (e.g. ASCII) an array of fixed size (256) replaces the hash map, which is effectively O(1) auxiliary space.
Q: What if the input string is empty?
A: The loop never executes, and max_len remains 0, which is the correct answer.
Q: How would the approach change if we needed the actual substring, not just its length?
A: Track the left/right bounds whenever max_len updates, then slice s[left:right+1] at the end.
Q: What if we wanted the longest substring with at most k repeating characters instead of zero?
A: Generalize to a frequency-count sliding window (like "longest substring with at most K distinct characters") that shrinks the window only when the constraint is violated.
Quick Revision
- Problem: find the length of the longest substring with all unique characters.
- Use a sliding window
[left, right]and a hash map ofchar -> last index seen. - On seeing a repeat within the window, jump
lefttolast_seen[c] + 1. - Always update
last_seen[c] = rightandmax_lenafter processing each character. - Runs in O(n) time since
leftandrighteach move forward at most n times. - Space is O(min(m, n)) — bounded by alphabet size or string length, whichever is smaller.
- Edge cases: empty string → 0; all same character → 1; all distinct → n.
- Pattern generalizes to many "longest/shortest window satisfying a condition" problems.
Related Problems
- Same sliding-window-with-hashmap pattern as problems like "Longest Substring with At Most K Distinct Characters" and "Minimum Window Substring."
- Related substring-family problems in this set: 5 - Longest Palindromic Substring and 718 - Maximum Length Of Repeated Subarray.