title: Longest Substring Without Repeating Characters slug: longest-substring-without-repeating difficulty: medium leetcode_id: 3 leetcode_url: https://leetcode.com/problems/longest-substring-without-repeating-characters/ categories: - strings - hash-tables patterns: - sliding-window description: | Given a string `s`, find the length of the longest substring without repeating characters. constraints: | - 0 <= s.length <= 5 * 10^4 - s consists of English letters, digits, symbols and spaces examples: - input: 's = "abcabcbb"' output: "3" explanation: "The answer is 'abc', with length 3." - input: 's = "bbbbb"' output: "1" explanation: "The answer is 'b', with length 1." - input: 's = "pwwkew"' output: "3" explanation: "The answer is 'wke', with length 3." explanation: approach: | 1. Use a sliding window with left and right pointers 2. Maintain a set of characters in the current window 3. Expand right pointer, adding characters to the set 4. When a duplicate is found, shrink from left until duplicate is removed 5. Track maximum window size throughout intuition: | We're looking for the longest contiguous substring where all characters are unique. A sliding window naturally represents a substring. When we encounter a duplicate, the current window is invalid. Instead of restarting from scratch, we shrink the window from the left until the duplicate is removed. This way, we never revisit characters unnecessarily. common_pitfalls: - title: Resetting the window incorrectly description: | When finding a duplicate, don't start over from the next character. Instead, shrink from the left until the duplicate is removed. wrong_approach: "left = right when duplicate found" correct_approach: "Increment left until duplicate is out of window" - title: Not handling empty string description: | An empty string should return 0. Make sure the algorithm handles this. - title: Off-by-one in length calculation description: | Window length is right - left + 1, or just track max before removing. key_takeaways: - Sliding window is ideal for substring problems with constraints - Use a set or map to track elements in current window - Shrinking from one end maintains the contiguous property - This pattern appears in many "longest/shortest with constraint" problems time_complexity: "O(n)" space_complexity: "O(min(m, n))" complexity_explanation: | Time: Each character is visited at most twice (once by right, once by left). Space: The set holds at most min(n, m) characters where m is the charset size. solutions: - approach_name: Sliding Window with Set (Optimal) is_optimal: true code: | def length_of_longest_substring(s: str) -> int: char_set = set() left = 0 max_length = 0 for right in range(len(s)): while s[right] in char_set: char_set.remove(s[left]) left += 1 char_set.add(s[right]) max_length = max(max_length, right - left + 1) return max_length explanation: | Expand window by moving right pointer. When duplicate found, shrink from left until window is valid again. - approach_name: Optimized with Hash Map is_optimal: true code: | def length_of_longest_substring(s: str) -> int: char_index = {} left = 0 max_length = 0 for right, char in enumerate(s): if char in char_index and char_index[char] >= left: left = char_index[char] + 1 char_index[char] = right max_length = max(max_length, right - left + 1) return max_length explanation: | Store the last index of each character. Jump left pointer directly past the duplicate instead of shrinking one by one.