substring
longest substring
non-repeating characters
string manipulation
coding challenge

Find longest substring without repeating characters

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The standard solution to the longest-substring-without-repeating-characters problem is a sliding window. The idea is to keep a window of unique characters, expand it as long as the next character is new, and shrink or jump the left side when a duplicate appears. That gives a linear-time solution instead of checking every possible substring.

Understand why brute force is too slow

A brute-force solution inspects every substring and checks whether it contains duplicates. That is easy to understand, but it becomes expensive quickly because there are many substrings and each duplicate check costs more work.

For interviews or production code, brute force is mainly useful as a correctness baseline, not as the final algorithm.

Solve it with a sliding window and last-seen positions

The efficient pattern stores the last index where each character appeared. When a duplicate appears inside the current window, move the left boundary just past the previous occurrence.

python
1def length_of_longest_substring(text: str) -> int:
2    last_seen = {}
3    left = 0
4    best = 0
5
6    for right, char in enumerate(text):
7        if char in last_seen and last_seen[char] >= left:
8            left = last_seen[char] + 1
9
10        last_seen[char] = right
11        best = max(best, right - left + 1)
12
13    return best
14
15print(length_of_longest_substring("abcabcbb"))
16print(length_of_longest_substring("bbbbb"))
17print(length_of_longest_substring("pwwkew"))

This runs in O(n) time because each index is processed once, and the left pointer never moves backward.

Why jumping the left pointer is better than deleting one by one

Some sliding-window solutions remove characters from a set one step at a time when a duplicate is found. That also works, but the last-seen-index approach is usually cleaner because it jumps directly to the right place.

Example with "abba":

  • read a, window is a
  • read b, window is ab
  • read second b, move left from 0 to 2
  • continue with a

The important detail is the condition last_seen[char] >= left. Without that guard, an old occurrence outside the current window could move left backward incorrectly.

Return the substring itself, not just the length

Sometimes the problem asks for the actual substring. Track the best start index while updating the best length.

python
1def longest_substring(text: str) -> str:
2    last_seen = {}
3    left = 0
4    best_start = 0
5    best_length = 0
6
7    for right, char in enumerate(text):
8        if char in last_seen and last_seen[char] >= left:
9            left = last_seen[char] + 1
10
11        last_seen[char] = right
12        current_length = right - left + 1
13
14        if current_length > best_length:
15            best_length = current_length
16            best_start = left
17
18    return text[best_start:best_start + best_length]
19
20print(longest_substring("abcabcbb"))

That version is often more practical because users usually care about the substring, not only the number.

Edge cases to handle explicitly

The sliding window handles common edge cases naturally, but it is worth thinking through them:

  • empty string should return 0 or ""
  • repeated single character such as "aaaa" should return 1
  • duplicates outside the current window must not force the left pointer backward

Testing these cases prevents subtle bugs in the update condition.

Character model considerations

In most interview settings, treating a Python string as a sequence of characters is enough. In production systems with Unicode-heavy text, the definition of a "character" can be more complicated because user-perceived characters may span multiple code points. The algorithmic idea stays the same, but the tokenization step may need to operate on grapheme clusters rather than raw code points.

That nuance matters mostly in internationalized text processing, not in the core interview problem.

Common Pitfalls

  • Resetting the entire window when a duplicate appears instead of moving only the left boundary.
  • Forgetting the last_seen[char] >= left check and moving the window backward incorrectly.
  • Returning the length when the caller actually needs the substring itself.
  • Using brute force for large inputs when a linear sliding window is available.
  • Missing empty-string and repeated-character edge cases in tests.

Summary

  • Use a sliding window with last-seen character indices for the standard efficient solution.
  • The algorithm runs in O(n) time and O(k) space, where k depends on the character set used.
  • Move the left boundary only when the duplicate is inside the current window.
  • Track the best start index as well if you need the substring itself.
  • Test edge cases such as empty input and repeated characters to verify the window logic.

Course illustration
Course illustration

All Rights Reserved.