|
| 1 | +""" |
| 2 | +159. Longest Substring with At Most Two Distinct Characters |
| 3 | +
|
| 4 | +https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters |
| 5 | +
|
| 6 | +NOTES |
| 7 | + * Use a sliding window. |
| 8 | +
|
| 9 | +This one is pretty easy. As with other substring problems, we can use a hash |
| 10 | +map to track the frequency of characters in the current substring. Since, |
| 11 | +however, we are only concerned with at most two characters, we can just use two |
| 12 | +variables. Similar to 'Longest Substring Without Repeating Characters', we |
| 13 | +maintain the index of the last occurrence of each character in order to adjust |
| 14 | +the sliding window if the substring becomes invalid. In addition, I've added a |
| 15 | +solution that generalizes to 'k' distinct characters. |
| 16 | +""" |
| 17 | + |
| 18 | + |
| 19 | +class Solution: |
| 20 | + def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int: |
| 21 | + # c1 and c2 hold the index of the last occurrence of a character. |
| 22 | + left, right, c1, c2, maximum_size = 0, 0, 0, 0, 0 |
| 23 | + |
| 24 | + while right < len(s): |
| 25 | + # NOTE: s[c1] != s[c2] handles the case where `s` starts with |
| 26 | + # repeating characters |
| 27 | + if s[right] not in [s[c1], s[c2]] and s[c1] != s[c2]: |
| 28 | + # Move `left` to the character after the next index. |
| 29 | + if c1 < c2: |
| 30 | + left, c1, c2 = c1 + 1, c2, right |
| 31 | + else: |
| 32 | + left, c2, c1 = c2 + 1, c1, right |
| 33 | + # Update the index of `c1` and `c2`, the last occurrence of each |
| 34 | + # character. |
| 35 | + elif s[right] == s[c1]: |
| 36 | + c1 = right |
| 37 | + else: |
| 38 | + c2 = right |
| 39 | + |
| 40 | + maximum_size = max(maximum_size, right - left + 1) |
| 41 | + right += 1 |
| 42 | + |
| 43 | + return maximum_size |
| 44 | + |
| 45 | + |
| 46 | +class GeneralSolution: |
| 47 | + def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int: |
| 48 | + left, right, maximum_size = 0, 0, 0 |
| 49 | + |
| 50 | + # Maintain a mapping of character -> index of last occurrence. |
| 51 | + d: dict[str, int] = {} |
| 52 | + |
| 53 | + while right < len(s): |
| 54 | + d[s[right]] = right |
| 55 | + |
| 56 | + # If the map ever contains more than two keys, then the substring |
| 57 | + # contains more than two distinct characters. |
| 58 | + if len(d) > 2: |
| 59 | + # Move `left` to the character after the next index. |
| 60 | + next_index = min(d.values()) |
| 61 | + left = next_index + 1 |
| 62 | + # Remove the character from the hash map. |
| 63 | + del d[s[next_index]] |
| 64 | + |
| 65 | + maximum_size = max(maximum_size, right - left + 1) |
| 66 | + right += 1 |
| 67 | + |
| 68 | + return maximum_size |
0 commit comments