Substring Search Patterns in DSA C++ - Time & Space Complexity
We want to understand how long it takes to find a smaller string inside a bigger string.
How does the time needed change when the strings get longer?
Analyze the time complexity of the following code snippet.
bool containsSubstring(const std::string &text, const std::string &pattern) {
int n = text.size();
int m = pattern.size();
for (int i = 0; i <= n - m; i++) {
int j = 0;
while (j < m && text[i + j] == pattern[j]) {
j++;
}
if (j == m) return true;
}
return false;
}
This code checks if the pattern appears anywhere inside the text by comparing characters one by one.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The outer loop moves through each possible start position in the text.
- How many times: Up to n - m + 1 times, where n is text length and m is pattern length.
- Secondary operation: The inner while loop compares characters of pattern and text.
- How many times: Up to m times for each outer loop iteration in the worst case.
- Dominant operation: The nested character comparisons inside the loops.
As the text and pattern get longer, the number of character comparisons grows quickly.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 (text), 3 (pattern) | Up to 8 * 3 = 24 comparisons |
| 100 (text), 10 (pattern) | Up to 91 * 10 = 910 comparisons |
| 1000 (text), 50 (pattern) | Up to 951 * 50 = 47,550 comparisons |
Pattern observation: The operations grow roughly by multiplying text length by pattern length.
Time Complexity: O(n * m)
This means the time needed grows proportionally to the product of text length and pattern length.
[X] Wrong: "The search always takes time proportional to the text length only."
[OK] Correct: The pattern length matters too because each position in the text may require checking many characters of the pattern.
Understanding this helps you explain why simple substring search can be slow and why smarter algorithms exist.
"What if we used a more advanced algorithm like KMP? How would the time complexity change?"
Practice
Solution
Step 1: Understand substring search purpose
Substring search algorithms check if a smaller string (pattern) appears inside a bigger string (text).Step 2: Compare options with definition
Only To find if a smaller string exists inside a larger string describes finding a smaller string inside a larger one, which matches substring search.Final Answer:
To find if a smaller string exists inside a larger string -> Option DQuick Check:
Substring search = find smaller string inside larger [OK]
- Confusing substring search with sorting or reversing strings
- Thinking substring search counts characters instead of finding patterns
pattern is a substring of string text in C++?Solution
Step 1: Recall C++ substring search syntax
In C++,std::string::findreturns the position of the substring orstd::string::nposif not found.Step 2: Analyze each option
if (text.find(pattern) != std::string::npos) { /* found */ } usestext.find(pattern) != std::string::npos, which is correct. Others use invalid or non-existent methods.Final Answer:
if (text.find(pattern) != std::string::npos) { /* found */ } -> Option AQuick Check:
Use find() and compare with npos [OK]
- Using methods like contains or indexOf which don't exist in std::string
- Comparing find() result directly to true or false
std::string text = "hello world";
std::string pattern = "world";
size_t pos = text.find(pattern);
if (pos != std::string::npos) {
std::cout << pos << std::endl;
} else {
std::cout << -1 << std::endl;
}Solution
Step 1: Find substring position in text
The substring "world" starts at index 6 in "hello world" (counting from 0).Step 2: Check condition and output
Since find returns 6 (not npos), the code prints 6.Final Answer:
6 -> Option CQuick Check:
"world" starts at index 6 in "hello world" [OK]
- Counting index starting at 1 instead of 0
- Printing -1 when substring is actually found
std::string text = "example";
std::string pattern = "amp";
if (text.find(pattern) == -1) {
std::cout << "Not found" << std::endl;
} else {
std::cout << "Found" << std::endl;
}Solution
Step 1: Understand find() return value
std::string::find returns std::string::npos if substring not found, not -1.Step 2: Identify incorrect comparison
Comparing to -1 is wrong; must compare to std::string::npos for correctness.Final Answer:
Comparing find() result to -1 instead of std::string::npos -> Option AQuick Check:
Use npos, not -1, to check find() failure [OK]
- Using -1 instead of std::string::npos for not found
- Assuming find() returns boolean
// Patterns: ["he", "she", "his", "hers"] // Text: "ahishers"
Solution
Step 1: Understand multiple pattern search problem
Searching many patterns separately is inefficient; better to search all at once.Step 2: Identify best algorithm for multiple patterns
Aho-Corasick builds a combined automaton to find all patterns in one pass efficiently.Step 3: Compare other options
Naive and Rabin-Karp per pattern or repeated find calls are slower for many patterns.Final Answer:
Build an Aho-Corasick automaton for all patterns and search once -> Option BQuick Check:
Multiple patterns = Aho-Corasick automaton [OK]
- Using naive search for each pattern separately
- Applying single-pattern algorithms repeatedly
- Ignoring combined automaton approach
Ready to prove it?
Pass the test and this pattern moves unknown
