Longest Substring without Repeating Characters
Longest distinct-character substring via sliding window + last-seen index map.
3 min read
sliding-window string hash-map
Problem#
Return the length of the longest substring of s with no repeated characters.
Examples#
"abcabcbb"→3("abc")"bbbbb"→1"pwwkew"→3("wke")
Constraints#
0 <= s.length <= 5 * 10^4.
Approach#
Track last[c] = the last index we saw character c. When the current character was last seen inside the current window, jump left past that position. Otherwise grow.
Solution#
class Solution {public: int lengthOfLongestSubstring(string s) { int last[256]; fill(begin(last), end(last), -1); int left = 0, best = 0; for (int right = 0; right < (int)s.size(); ++right) { if (last[(unsigned char)s[right]] >= left) { left = last[(unsigned char)s[right]] + 1; } last[(unsigned char)s[right]] = right; best = max(best, right - left + 1); } return best; }};func lengthOfLongestSubstring(s string) int { var last [256]int for i := range last { last[i] = -1 } left, best := 0, 0 for right := 0; right < len(s); right++ { c := s[right] if last[c] >= left { left = last[c] + 1 } last[c] = right if right-left+1 > best { best = right - left + 1 } } return best}class Solution: def lengthOfLongestSubstring(self, s: str) -> int: last = [-1] * 256 left = 0 best = 0 for right, ch in enumerate(s): c = ord(ch) if last[c] >= left: left = last[c] + 1 last[c] = right if right - left + 1 > best: best = right - left + 1 return bestfunction lengthOfLongestSubstring(s) { const last = new Array(256).fill(-1); let left = 0, best = 0; for (let right = 0; right < s.length; right++) { const c = s.charCodeAt(right); if (last[c] >= left) left = last[c] + 1; last[c] = right; if (right - left + 1 > best) best = right - left + 1; } return best;}class Solution { public int lengthOfLongestSubstring(String s) { int[] last = new int[256]; Arrays.fill(last, -1); int left = 0, best = 0; for (int right = 0; right < s.length(); right++) { int c = s.charAt(right); if (last[c] >= left) left = last[c] + 1; last[c] = right; if (right - left + 1 > best) best = right - left + 1; } return best; }}function lengthOfLongestSubstring(s: string): number { const last: number[] = new Array(256).fill(-1); let left = 0, best = 0; for (let right = 0; right < s.length; right++) { const c = s.charCodeAt(right); if (last[c] >= left) left = last[c] + 1; last[c] = right; if (right - left + 1 > best) best = right - left + 1; } return best;}Editorial#
The “jump” pattern avoids a shrink loop: we leap left directly past the previous occurrence (only if that occurrence is inside the current window — older sightings don’t matter). Each character is processed once on each pointer’s traversal → O(n).
Complexity#
- Time: O(n).
- Space: O(|Σ|).
Concept revision#
Related#