Longest Substring Without Repeating Characters
Medium · Sliding Window · Explanation and code example
Sliding Window (Optimal)
How it works
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.
Steps
- 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.
Complexity
- Time complexity:
O(n) - Space complexity:
O(m)
Where
nis the length of the string andmis the total number of unique characters in the string.
Things to watch for
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.
Python code example
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
mp = {}
l = 0
res = 0
for r in range(len(s)):
if s[r] in mp:
l = max(mp[s[r]] + 1, l)
mp[s[r]] = r
res = max(res, r - l + 1)
return res
C++ code example
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> mp;
int l = 0, res = 0;
for (int r = 0; r < s.size(); r++) {
if (mp.find(s[r]) != mp.end()) {
l = max(mp[s[r]] + 1, l);
}
mp[s[r]] = r;
res = max(res, r - l + 1);
}
return res;
}
};
Source and license
Adapted from NeetCode’s source · MIT license. Node types are supplied by LeetCode where needed.