Remove substrings inside a list with better than On2 complexity
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
When working with strings in Python, one may encounter the problem of needing to remove substrings within a list efficiently. The naive approach to solving this task is evaluating if each string in a list occurs in another string in the list, leading to time complexity, as each string in the list is compared with every other string. However, this article explores strategies that achieve better than complexity.
Understanding the Problem
Assume we have a list of strings, and we aim to remove strings that are substrings of another string within the same list. For example:
In the example above, "app" is a substring of "apple", and "can" is a substring of "candy". These substrings should be removed from the resulting list.
Naive Approach: Nested Loops
The most straightforward approach is to use nested loops:
The nested loops result in complexity, which is inefficient for large lists. Therefore, alternatives with better performance are desirable.
Efficient Solution: Trie-based Approach
A Trie (prefix tree) is a data structure that can efficiently store strings for fast search of substrings. Here’s how to use a Trie to filter substrings efficiently:
- Construct a Trie: Insert each string in the list into the Trie.
- Search for Non-Substrings: For each string, search in Trie to find if it is not a prefix or an inner node that completely matches another string.
- Build the Result: Collect strings that aren’t found as internal node substrings.
Trie Construction
A Trie is built by inserting characters of each string hierarchically:
Complexity and Performance
The Trie-based solution can give a better average-case complexity. Trie insertions and checks are , where is the average length of the strings. Building the Trie for all strings is then .
Example Implementation
Alternative Methods
Suffix Array
Suffix arrays are another approach for dealing with substring matching problems. Constructing a suffix array takes , and searching can be done in , but it’s more suitable for large texts where preprocessing is amortized over many searches.
Sorting and String Matching
Sort the strings by length (longest first) and use a hash set to track the processed strings. This can optimize some of the operations but is generally less efficient than a Trie.
Summary Table
| Method | Time Complexity | Space Complexity | Best Use Case |
| Nested Loops | Small lists, readability over performance | ||
| Trie-based | Moderate-sized lists, fast insert/search | ||
| Suffix Array | Large strings or texts, less space efficiency | ||
| Sorting & Hashing | Depends (usually faster) | Small to mid-sized lists, simple implementation |
Conclusion
Efficiently removing substrings from a list requires strategic use of data structures. The Trie-based approach allows for scalable handling of medium-sized datasets, significantly improving performance over naive methods. However, the choice of method may depend on specific use case requirements such as dataset size and complexity tolerance.
Related reading
- Remove the minimum number of blades
- Removing almost duplicate strings in subquadratic time
- Removing duplicates in lists
- Removing duplicates in lists
- Remove unused references using
- Removing duplicate elements from an array in Swift
- Reorder a string by half the character
- Reorder vector using a vector of indices

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.