16. Longest Substring Without Repeating Characters
View on NeetCode
View on LeetCode
Problem
Given a string s, find the length of the longest substring without repeating characters.
Example 1:
Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Example 2:
Input: s = "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:
Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.
Constraints:
0 <= s.length <= 5 * 10^4sconsists of English letters, digits, symbols and spaces.
Solution
Approach: Sliding Window with Hash Set
The key insight is to use a sliding window technique with a hash set to track characters in the current window. We expand the window by moving the right pointer and shrink it when we encounter a duplicate character.
We maintain:
left: left boundary of the windowchar_set: set of characters in the current windowmax_length: maximum length found so far
For each character:
- If it’s not in the set, add it and update max length
- If it’s a duplicate, remove characters from the left until the duplicate is removed
Implementation
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
char_set = set()
left = 0
max_length = 0
for right in range(len(s)):
# Shrink window until no duplicates
while s[right] in char_set:
char_set.remove(s[left])
left += 1
# Add current character
char_set.add(s[right])
# Update max length
max_length = max(max_length, right - left + 1)
return max_length
Alternative (Using Hash Map for Index Tracking):
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
char_index = {}
left = 0
max_length = 0
for right in range(len(s)):
# If character seen and within window, move left
if s[right] in char_index and char_index[s[right]] >= left:
left = char_index[s[right]] + 1
# Update character's latest index
char_index[s[right]] = right
# Update max length
max_length = max(max_length, right - left + 1)
return max_length
Complexity Analysis
- Time Complexity: O(n), where n is the length of the string. Each character is visited at most twice (once by right pointer, once by left pointer).
- Space Complexity: O(min(m, n)), where m is the size of the character set. In the worst case, we store all unique characters in the set.
Key Insights
-
Sliding Window Pattern: Expand the window with the right pointer and shrink it with the left pointer when we find a duplicate. This maintains the invariant that our window always contains unique characters.
-
Set vs Map: Using a set is simpler and works well. Using a map to store indices allows us to jump the left pointer directly to the position after the duplicate, potentially skipping unnecessary iterations.
-
Window Size Calculation: The length of the current window is
right - left + 1. We track the maximum of all window sizes. -
Edge Cases: Empty string returns 0, single character returns 1, all duplicates returns 1.