string manipulation
algorithm optimization
substrings
duplicate question
coding efficiency

Find all possible substring in fastest way

Master System Design with Codemia

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

Introduction

Generating all substrings of a string is inherently expensive because there are n*(n+1)/2 substrings for length n. That means no algorithm can list all substrings in less than quadratic output size. So the "fastest way" depends on what you actually need:

  • enumerate all substrings,
  • count unique substrings,
  • search/query substrings efficiently.

If you only need counts or queries, advanced structures (suffix array/tree/automaton) can avoid explicit materialization.

Core Sections

1. Optimal enumeration baseline (output-sensitive)

For raw enumeration, nested loops are the direct method.

python
1def all_substrings(s: str):
2    n = len(s)
3    for i in range(n):
4        for j in range(i + 1, n + 1):
5            yield s[i:j]
6
7print(list(all_substrings("abc")))
8# ['a', 'ab', 'abc', 'b', 'bc', 'c']

Complexity:

  • number of substrings: O(n^2)
  • total copied characters in naive slicing: up to O(n^3) in some languages/runtime contexts.

In Python, substring slicing creates new strings, so memory/time can be high for large n.

2. Avoid materializing when not needed

If downstream logic only checks predicates or streams results, keep generator style and process on the fly.

python
1def count_with_vowel_start(s: str) -> int:
2    vowels = set("aeiou")
3    c = 0
4    for sub in all_substrings(s):
5        if sub[0] in vowels:
6            c += 1
7    return c

Avoid list(all_substrings(...)) for large strings.

For deduplicated unique substrings, a set works but can explode memory:

python
unique = set(all_substrings("banana"))
print(len(unique))

3. Faster specialized structures for query/count use cases

Suffix array/tree/automaton can answer many substring problems without generating every substring explicitly.

Example: counting distinct substrings with suffix automaton is near linear in string length.

Conceptual direction (not full implementation):

  • build suffix automaton in O(n),
  • distinct substring count from state lengths.

For repeated substring search across one large text, suffix array or suffix tree provides much faster query performance than brute-force substring generation.

4. Practical performance tips

  • Clarify exact requirement before coding.
  • Use generators for streaming.
  • For huge strings, write in compiled language or use C-accelerated libraries.
  • Benchmark realistic input sizes.
python
1import time
2
3s = "a" * 5000
4t0 = time.time()
5_ = sum(1 for _ in all_substrings(s))
6print("elapsed", time.time() - t0)

This quickly shows quadratic growth in action.

Common Pitfalls

  • Asking for "fastest" while still requiring full explicit list of all substrings.
  • Materializing all substrings in memory and hitting RAM limits on large inputs.
  • Ignoring string-copy cost and assuming two-loop enumeration is only O(n^2) in practice.
  • Using brute force when requirement is actually query/count, where suffix structures are superior.
  • Benchmarking with tiny strings and extrapolating incorrectly to production sizes.

Summary

You cannot beat quadratic output size when enumerating every substring. The best practical approach is to stream substrings lazily and avoid materialization unless necessary. If your real goal is counting or searching, use suffix-based data structures to achieve dramatically better performance characteristics.

For very large text processing tasks, representation choices matter. Instead of slicing strings repeatedly, some systems operate on index pairs (start, end) and only materialize substrings when required. This can significantly reduce memory pressure when downstream processing can work with offsets. It also enables compatibility with memory-mapped files and streaming parsers where copying substrings is expensive.

If duplicates are important, consider rolling hash or suffix-based indexes to avoid repeated comparisons of long substrings. These approaches increase implementation complexity, so they are most useful when performance constraints are strict. Benchmarking with realistic workloads is essential before committing to advanced structures.

For interview and teaching contexts, explicitly separating "enumeration" and "query" problems avoids confusion and leads to better algorithm choices.

Always align algorithm choice with concrete output requirements.


Course illustration
Course illustration

All Rights Reserved.