Longest Substring Without Repeating Characters
You're given a string s. Find the length of the longest substring in which no character appears more than once. A substring is a contiguous run of characters, so skipping characters is not allowed. Every character counts, including spaces, digits and symbols, and case matters ('a' and 'A' are different). Return only the length. An empty string has answer 0.
Examples
s = "abcabcbb" returns 3
"abc", "bca" and "cab" all have 3 distinct characters. Every substring of length 4 repeats a letter (for example "abca" repeats a), so 3 is the best.
s = "bbbbb" returns 1
Every character is b, so any substring longer than 1 repeats it. The answer is "b", length 1.
s = "pwwkew" returns 3
"wke" (indices 2 to 4) is a longest answer, length 3. "pwke" has no repeats but skips the second w, so it is not a substring and doesn't count.
Constraints
- 0 <= s.length <= 5 * 10^4
- s consists of English letters, digits, symbols, and spaces.
Hints
Think about a contiguous range of characters that stays unique, what happens when a duplicate enters?
Use a hash map from character to its last seen index, and maintain two indices bounding the current range.
Keep left and right pointers. For each right, if s[right] was last seen at index >= left, set left = last_seen + 1. Record the index, then update the best length as right - left + 1.
Drill This: Your Approach First
Approach
Keep a range [left, right] with no repeats and a map from each character to the index where it was last seen. For each right, if s[right] was last seen at an index >= left, that repeat is inside the range, so jump left to one past it. Then record the new index and update the best length as right - left + 1. Each index is visited once; k is the size of the character set.
Time
O(n)
Space
O(min(n, k))
Pitfall
Solutions
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> last = new HashMap<>();
int left = 0, best = 0;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
if (last.containsKey(c) && last.get(c) >= left) {
left = last.get(c) + 1;
}
last.put(c, right);
best = Math.max(best, right - left + 1);
}
return best;
}
}class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
last = {}
left = best = 0
for right, c in enumerate(s):
if c in last and last[c] >= left:
left = last[c] + 1
last[c] = right
best = max(best, right - left + 1)
return best