|  | 
|  | 1 | +# Longest Substring Without Repeating Characters | 
|  | 2 | +Given a string s, find the length of the longest substring without repeating characters. | 
|  | 3 | + | 
|  | 4 | +### Constraints: | 
|  | 5 | +- 0 <= s.length <= 5 * 10^4 | 
|  | 6 | +- s consists of English letters, digits, symbols, and spaces. | 
|  | 7 | + | 
|  | 8 | +### Examples | 
|  | 9 | +```javascript | 
|  | 10 | +Input: s = "abcabcbb" | 
|  | 11 | +Output: 3 | 
|  | 12 | +Explanation: The answer is "abc", with the length of 3. | 
|  | 13 | + | 
|  | 14 | +Input: s = "bbbbb" | 
|  | 15 | +Output: 1 | 
|  | 16 | +Explanation: The answer is "b", with the length of 1. | 
|  | 17 | + | 
|  | 18 | +Input: s = "pwwkew" | 
|  | 19 | +Output: 3 | 
|  | 20 | +Explanation: The answer is "wke", with the length of 3.  | 
|  | 21 | +Notice that the answer must be a substring, "pwke" is a subsequence and not a substring. | 
|  | 22 | +``` | 
|  | 23 | + | 
|  | 24 | +## Approaches to Solve the Problem | 
|  | 25 | +### Approach 1: Brute Force (Inefficient) | 
|  | 26 | +##### Intuition: | 
|  | 27 | +A simple brute-force solution is to check every possible substring, and for each substring, check if it contains duplicate characters. The maximum length of a substring without repeating characters is tracked. | 
|  | 28 | + | 
|  | 29 | +Steps: | 
|  | 30 | +1. Use two nested loops to generate all possible substrings. | 
|  | 31 | +2. For each substring, check if it contains duplicate characters by using a set or dictionary. | 
|  | 32 | +3. Track the maximum length of substrings without duplicates. | 
|  | 33 | +##### Time Complexity: | 
|  | 34 | +O(n²) for checking all substrings and validating each one. | 
|  | 35 | +##### Space Complexity: | 
|  | 36 | +O(n) for storing characters in a set or dictionary while checking each substring. | 
|  | 37 | +##### Python Code: | 
|  | 38 | +```python | 
|  | 39 | +def lengthOfLongestSubstring(s: str) -> int: | 
|  | 40 | +    max_len = 0 | 
|  | 41 | +    n = len(s) | 
|  | 42 | +     | 
|  | 43 | +    for i in range(n): | 
|  | 44 | +        seen = set() | 
|  | 45 | +        for j in range(i, n): | 
|  | 46 | +            if s[j] in seen: | 
|  | 47 | +                break | 
|  | 48 | +            seen.add(s[j]) | 
|  | 49 | +            max_len = max(max_len, j - i + 1) | 
|  | 50 | +     | 
|  | 51 | +    return max_len | 
|  | 52 | +``` | 
|  | 53 | +### Approach 2: Sliding Window with Hash Set (Optimal) | 
|  | 54 | +##### Intuition:  | 
|  | 55 | +The brute-force approach is inefficient because it recalculates the substring from scratch each time. We can improve this by using a sliding window technique, where we keep track of the current substring using two pointers, left and right, and adjust the window as necessary. A hash set is used to track characters in the current window, allowing us to efficiently check for duplicates. | 
|  | 56 | + | 
|  | 57 | +1. Use two pointers (left and right) to create a window of characters. | 
|  | 58 | +2. Expand the window by moving the right pointer. | 
|  | 59 | +3. If a duplicate character is found, shrink the window from the left by moving the left pointer until the duplicate is removed. | 
|  | 60 | +4. Track the maximum length of the window during this process. | 
|  | 61 | + | 
|  | 62 | +Steps: | 
|  | 63 | +1. Initialize a set to store the characters in the current window. | 
|  | 64 | +2. Move the right pointer to expand the window. | 
|  | 65 | +3. If the character at right is already in the set, move the left pointer to shrink the window until the character is removed. | 
|  | 66 | +4. Keep updating the maximum length of the window. | 
|  | 67 | +##### Visualization: | 
|  | 68 | +```perl | 
|  | 69 | +For s = "abcabcbb": | 
|  | 70 | + | 
|  | 71 | +Initial state: left = 0, right = 0, window = "" | 
|  | 72 | +Step 1: Expand window to "a" | 
|  | 73 | +Step 2: Expand window to "ab" | 
|  | 74 | +Step 3: Expand window to "abc" (max_len = 3) | 
|  | 75 | +Step 4: Encounter duplicate 'a', move left to 1 (window = "bca") | 
|  | 76 | +Step 5: Expand window to "bcab" → encounter duplicate 'b', move left to 2 (window = "cab") | 
|  | 77 | +Continue until the entire string is processed. | 
|  | 78 | +``` | 
|  | 79 | +##### Time Complexity: | 
|  | 80 | +O(n), where n is the length of the string. We traverse the string once with the sliding window. | 
|  | 81 | +##### Space Complexity: | 
|  | 82 | +O(min(n, m)), where n is the length of the string and m is the size of the character set (e.g., 26 for lowercase English letters). | 
|  | 83 | +##### Python Code: | 
|  | 84 | +```python | 
|  | 85 | +def lengthOfLongestSubstring(s: str) -> int: | 
|  | 86 | +    char_set = set() | 
|  | 87 | +    left = 0 | 
|  | 88 | +    max_len = 0 | 
|  | 89 | +     | 
|  | 90 | +    for right in range(len(s)): | 
|  | 91 | +        # Shrink the window if we encounter a duplicate character | 
|  | 92 | +        while s[right] in char_set: | 
|  | 93 | +            char_set.remove(s[left]) | 
|  | 94 | +            left += 1 | 
|  | 95 | +         | 
|  | 96 | +        # Add the current character to the window | 
|  | 97 | +        char_set.add(s[right]) | 
|  | 98 | +         | 
|  | 99 | +        # Update the maximum length | 
|  | 100 | +        max_len = max(max_len, right - left + 1) | 
|  | 101 | +     | 
|  | 102 | +    return max_len | 
|  | 103 | +``` | 
|  | 104 | +### Approach 3: Sliding Window with Hash Map | 
|  | 105 | +##### Intuition:  | 
|  | 106 | +A further optimization can be made by using a hash map to store the last index of each character. This allows us to move the left pointer directly to the position after the last occurrence of the duplicate character, rather than shrinking the window one character at a time. | 
|  | 107 | + | 
|  | 108 | +Steps: | 
|  | 109 | +1. Initialize a hash map to store the last index of each character. | 
|  | 110 | +2. Move the right pointer to expand the window. | 
|  | 111 | +3. If a duplicate character is found, move the left pointer directly to the position after the last occurrence of the duplicate. | 
|  | 112 | +4. Track the maximum length of the window. | 
|  | 113 | +##### Visualization: | 
|  | 114 | +```perl | 
|  | 115 | +For s = "abcabcbb": | 
|  | 116 | + | 
|  | 117 | +Initial state: left = 0, right = 0, window = "", last_occurrence = {} | 
|  | 118 | +Step 1: Expand window to "a" → last_occurrence['a'] = 0 | 
|  | 119 | +Step 2: Expand window to "ab" → last_occurrence['b'] = 1 | 
|  | 120 | +Step 3: Expand window to "abc" → last_occurrence['c'] = 2 | 
|  | 121 | +Step 4: Encounter duplicate 'a', move left to 1 (after last 'a') | 
|  | 122 | +Continue until the entire string is processed. | 
|  | 123 | +``` | 
|  | 124 | +##### Time Complexity: | 
|  | 125 | +O(n), as we still traverse the string once, but this time we move the left pointer more efficiently. | 
|  | 126 | +##### Space Complexity: | 
|  | 127 | +O(min(n, m)), where n is the length of the string and m is the size of the character set. | 
|  | 128 | +##### Python Code: | 
|  | 129 | +```python | 
|  | 130 | +def lengthOfLongestSubstring(s: str) -> int: | 
|  | 131 | +    char_index_map = {} | 
|  | 132 | +    left = 0 | 
|  | 133 | +    max_len = 0 | 
|  | 134 | +     | 
|  | 135 | +    for right in range(len(s)): | 
|  | 136 | +        # If the character is already in the map, move the left pointer | 
|  | 137 | +        if s[right] in char_index_map: | 
|  | 138 | +            left = max(left, char_index_map[s[right]] + 1) | 
|  | 139 | +         | 
|  | 140 | +        # Update the last occurrence of the current character | 
|  | 141 | +        char_index_map[s[right]] = right | 
|  | 142 | +         | 
|  | 143 | +        # Update the maximum length of the window | 
|  | 144 | +        max_len = max(max_len, right - left + 1) | 
|  | 145 | +     | 
|  | 146 | +    return max_len | 
|  | 147 | +``` | 
|  | 148 | +## Summary | 
|  | 149 | +| Approach                         | Time Complexity | Space Complexity | | 
|  | 150 | +|-----------------------------------|-----------------|------------------| | 
|  | 151 | +| Brute Force	                    | 	O(n²)      | O(n)             | | 
|  | 152 | +| Sliding Window with Hash Set		                   | O(n)            | O(min(n, m))             | | 
|  | 153 | +| Sliding Window with Hash Map		                   | O(n)            | O(min(n, m))             | | 
|  | 154 | + | 
|  | 155 | +The Sliding Window with Hash Map is the most efficient approach because it uses a single pass over the string and minimizes the movement of the left pointer by jumping directly to the correct position. | 
0 commit comments