Learning Outcome
After this lesson, you should be able to maintain a duplicate-free window and move the left boundary only when a repeated character breaks the window.
Problem Statement
Given a string s, return the length of the longest substring without repeating characters.
| Input | Output | Why |
|---|---|---|
"abcabcbb" | 3 | The longest duplicate-free substring is "abc". |
"bbbbb" | 1 | Only one repeated character can be kept at a time. |
Brute Force Approach
Start from every index and extend until a duplicate appears. Track the maximum valid length.
This repeats scans from many start positions, so the worst-case time is O(n^2).
Optimized Approach
Use a sliding window [left, right]. Store the last index where each character appeared. When the current character was seen inside the current window, move left just after that old index.
Never move left backward. That one rule keeps the window valid and linear.
Exact Pseudocode
lastSeen = empty map
left = 0
best = 0
for right from 0 to length(s) - 1:
char = s[right]
if char exists in lastSeen and lastSeen[char] >= left:
left = lastSeen[char] + 1
lastSeen[char] = right
best = max(best, right - left + 1)
return best
Reference Code
class Solution:
def lengthOfLongestSubstring(self, s):
last_seen = {}
left = 0
best = 0
for right, ch in enumerate(s):
if ch in last_seen and last_seen[ch] >= left:
left = last_seen[ch] + 1
last_seen[ch] = right
best = max(best, right - left + 1)
return bestSample Dry Run
| right | char | left | window | best |
|---|---|---|---|---|
| 0 | a | 0 | a | 1 |
| 1 | b | 0 | ab | 2 |
| 2 | c | 0 | abc | 3 |
| 3 | a | 1 | bca | 3 |
| 4 | b | 2 | cab | 3 |
Complexity
| Measure | Value | Reason |
|---|---|---|
| Time | O(n) | Each index is processed once. |
| Space | O(k) | The map stores last positions for distinct characters. |
Edge Cases
- Empty string returns
0. - All characters same returns
1. - Repeated character appears before the current window and should not move
leftbackward.
Interview Checklist
- Define the window invariant: no duplicate characters inside it.
- Use last seen index to jump
left. - Update answer after fixing the window.
FAQs
Why use last seen index instead of a set?
A set works too, but last seen index lets you jump the left boundary directly.
Why use max(left, lastSeen + 1) logic?
It prevents moving left backward when a duplicate is outside the current window.
What is the core pattern?
Sliding window with last-seen positions.