3. Longest Substring Without Repeating Characters - Explanation
Description
Given a string s, find the length of the longest substring without duplicate characters.
A substring is a contiguous sequence of characters within a string.
Example 1:
Input: s = "zxyzxyz"
Output: 3Explanation: The string "xyz" is the longest without duplicate characters.
Example 2:
Input: s = "xxxx"
Output: 1Constraints:
0 <= s.length <= 1000smay consist of printable ASCII characters.
Topics
Recommended Time & Space Complexity
You should aim for a solution with O(n) time and O(m) space, where n is the length of the string and m is the number of unique characters in the string.
Hint 1
A brute force solution would be to try the substring starting at index i and try to find the maximum length we can form without duplicates by starting at that index. We can use a hash set to detect duplicates in O(1) time. Can you think of a better way?
Hint 2
We can use the sliding window algorithm. Since we only care about substrings without duplicate characters, the sliding window can help us maintain valid substring with its dynamic nature.
Hint 3
We can iterate through the given string with index r as the right boundary and l as the left boundary of the window. We use a hash set to check if the character is present in the window or not. When we encounter a character at index r that is already present in the window, we shrink the window by incrementing the l pointer until the window no longer contains any duplicates. Also, we remove characters from the hash set that are excluded from the window as the l pointer moves. At each iteration, we update the result with the length of the current window, r - l + 1, if this length is greater than the current result.
Prerequisites
Before attempting this problem, you should be comfortable with:
- Sliding Window Technique - Used to maintain a window of unique characters that can expand and shrink dynamically
- Hash Set - Needed to track which characters are currently in the window for O(1) duplicate detection
- Hash Map (optional) - The optimal solution uses a map to store character indices for direct pointer jumps
1. Brute Force
Intuition
The brute-force idea is to try starting a substring at every index and keep extending it until we see a repeated character.
For each starting point, we use a set to track the characters we’ve seen so far.
As soon as a duplicate appears, that substring can’t grow anymore, so we stop and record its length.
By doing this for every index, we are guaranteed to find the longest valid substring, though the approach is slow.
Algorithm
- Initialize
res = 0to store the maximum length. - For each starting index
i:- Create an empty set
charSet. - Extend the substring by moving
jfromiforward:- If
s[j]is already in the set, break. - Otherwise, add it to the set.
- If
- Update
reswith the size ofcharSet.
- Create an empty set
- Return
resafter checking all starting positions.
Time & Space Complexity
- Time complexity:
- Space complexity:
Where is the length of the string and is the total number of unique characters in the string.
2. Sliding Window
Intuition
Instead of restarting at every index like brute force, we can keep one window that always has unique characters.
We expand the window by moving the right pointer.
If we ever see a repeated character, we shrink the window from the left until the duplicate is removed.
This way, the window always represents a valid substring, and we track its maximum size.
It's efficient because each character is added and removed at most once.
Algorithm
- Create an empty set
charSetand two pointers:l= left edge of the windowr= right edge that moves through the string
- For each
r:- While
s[r]is already in the set:- Remove
s[l]from the set and movelright.
- Remove
- Add
s[r]to the set. - Update the result with the window size:
r - l + 1.
- While
- Return the maximum window size found.
Time & Space Complexity
- Time complexity:
- Space complexity:
Where is the length of the string and is the total number of unique characters in the string.
3. Sliding Window (Optimal)
Intuition
Instead of removing characters one by one when we see a repeat, we can jump the left pointer directly to the correct position.
We keep a map that stores the last index where each character appeared.
When a character repeats, the earliest valid starting point moves to one position after its previous occurrence.
This lets us adjust the window in one step and always keep it valid, making the approach fast and clean.
Algorithm
- Create a map
mpto store the last index of each character. - Initialize:
l = 0for the start of the window,res = 0for the longest length.
- Loop through the string with index
r:- If
s[r]is already inmp, moveltomp[s[r]] + 1, but never backward. - Update
mp[s[r]] = r. - Update the longest length:
res = max(res, r - l + 1).
- If
- Return
resat the end.
Time & Space Complexity
- Time complexity:
- Space complexity:
Where is the length of the string and is the total number of unique characters in the string.
Common Pitfalls
Not Taking the Maximum When Jumping the Left Pointer
In the optimal sliding window approach, when you find a duplicate character, you should move the left pointer to max(left, lastIndex[char] + 1). Forgetting the max operation can cause the left pointer to move backwards if the duplicate character's last occurrence is before the current window start, leading to incorrect results.
Forgetting to Update the Character's Last Index
After processing each character, you must update its last seen index in the map, regardless of whether it was a duplicate. Failing to update the index means future duplicate checks will reference stale positions, causing incorrect window calculations.
Off-by-One in Window Size Calculation
When calculating the substring length, ensure you use right - left + 1 since both indices are inclusive. Using right - left will undercount the length by one, resulting in an answer that is consistently one less than correct.
Sign in to join the discussion