3. Longest Substring Without Repeating Characters
On LeetCode ->Reformulated question¶
Find the maximum length of a contiguous substring of s that contains no repeated character.
Example:
Key trick¶
Use a sliding window.
- Keep a left boundary of the current valid substring.
- For each character, if it was seen inside the current window, jump the left boundary right after its previous index.
- Track the best window length.
Trap¶
- Confusing substring with subsequence.
- Moving the left pointer backward instead of only forward.
- Resetting the whole window on a duplicate instead of shrinking just enough.
- Forgetting to handle duplicates that were seen before but are no longer inside the current window.
Why this question is interesting¶
It turns a naive \(O(n^2)\) scan into an \(O(n)\) solution with one pass.
- Good test of sliding window thinking.
- Good test of handling indices carefully.
Solve the problem with idiomatic python¶
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
# last index where each character appeared
last_seen = {}
left = 0
best = 0
for right, ch in enumerate(s):
# If ch is inside the current window, move left past it.
if ch in last_seen and last_seen[ch] >= left:
left = last_seen[ch] + 1
last_seen[ch] = right
best = max(best, right - left + 1)
return best
Pytest test¶
import pytest
@pytest.mark.parametrize(
("s", "expected"),
[
("", 0),
(" ", 1),
("a", 1),
("bbbbb", 1),
("abcabcbb", 3),
("pwwkew", 3),
("dvdf", 3),
("abba", 2),
("tmmzuxt", 5),
("anviaj", 5),
],
)
def test_lengthOfLongestSubstring(s, expected):
assert Solution().lengthOfLongestSubstring(s) == expected
Comment my solution¶
Your solution is correct on common cases, but it is more complicated than needed.
- The nested
forinsidewhilemakes the window logic harder to reason about. - Tracking both
sizeandend - startis redundant. - The duplicate handling is clever, but index-based last-seen tracking is simpler and more standard for interviews.
- Time complexity is still \(O(n)\), but the usual dictionary solution is shorter and easier to explain.
## Solution
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
longest = 0
start, end = 0, 0
seen, size = set(), 0
while end < len(s):
for _ in range(end, len(s)):
if s[end] in seen:
break
seen.add(s[end])
size += 1
end += 1
longest = max(longest, size)
if not end < len(s):
break
# Skip value equal to s[end] but at a previous
# index in the sliding window while still keeping
# it in seen
while s[start] != s[end]:
seen.remove(s[start])
start += 1
size -= 1
start += 1
end += 1
return longest
Solution().lengthOfLongestSubstring(" ") # 1
Solution().lengthOfLongestSubstring("a") # 1
Solution().lengthOfLongestSubstring("abcabcbb") # 3