Implement strStr asks you to do something every search box does: find where one string appears inside another. It is the gentlest possible introduction to string matching, and the naive solution teaches the "slide a window and compare" move you will reuse for KMP, Rabin-Karp, and more.
Problem. Given two strings text and pattern, return the index of the first occurrence of
pattern in text, or -1 if pattern is not present. (An empty pattern returns 0.)
Example: text = 'abaacaab', pattern = 'aab' → answer 5 (because text[5:8] = 'aab').
The slow way first
There is no clever trick hiding here at first — the most direct idea already works. Try every possible start position in the text. For a start index i, compare the pattern character by character against text[i], text[i+1], and so on. If all of them match, you found it; if any mismatches, give up on this start and try i + 1.
The only cost is that comparing can fail late. A start can match many characters and then mismatch on the very last one, so you redo work the next window. That makes the naive method O(n · m) in the worst case — but it is simple, correct, and exactly what an interviewer wants you to write before optimizing.
The idea: slide the pattern and compare
Picture the pattern printed on a strip of paper that you slide left to right under the text. At each position, walk a second pointer j across the pattern:
- While
text[i + j] == pattern[j], advancej. - If
jreaches the length of the pattern, every character lined up — returni. - The moment a character disagrees, stop, slide the strip one step right, and reset
jto 0.
The two indices have clear jobs: i chooses where the window begins, and j measures how far into the pattern we have matched so far.
Walk through it
Step through the animation. The pattern row slides under the text row. Green cells are characters that matched; the highlighted pair is the comparison happening right now. Watch start i = 2 match two characters and then fail on the last one — that near-miss is exactly the wasted work KMP later avoids. When i reaches 5, all three characters of aab line up, j runs off the end, and we return 5.
Pseudocode
n = length of text, m = length of pattern
for each start i from 0 to n - m:
j = 0
while j < m and text[i + j] == pattern[j]:
j = j + 1 # this character matched, look at the next
if j == m:
return i # the whole pattern fit here
return -1 # never matched anywhereThe Python solution
def str_str(text, pattern):
n, m = len(text), len(pattern)
for i in range(n - m + 1):
j = 0
while j < m and text[i + j] == pattern[j]:
j += 1
if j == m:
return i
return -1n - m + 1is the number of valid start positions — past that, the pattern would hang off the end of the text.jresets to0for every new start; it counts how many characters have matched in the current window.- The
whilekeeps comparing only while characters agree;j < mstops us from reading past the pattern. - If the loop ends with
j == m, every character matched, so the pattern begins ati— return it. - If no start ever produces
j == m, we fall out of theforand return-1.
Complexity
| Case | Time | Notes |
|---|---|---|
| Naive (this solution) | O(n · m) (moderate) | every window may compare m chars |
| Best / typical | near O(n) (moderate) | most windows mismatch on char 0 |
| KMP (advanced) | O(n + m) (moderate) | skips redundant comparisons |
O(1) (fast)The naive scan uses O(1) extra space — just two indices. Its weakness is the repeated work after a long partial match. KMP fixes that by precomputing a failure table so that after a mismatch it never re-checks characters it already knows agree, giving a linear O(n + m) total. For interviews, write the naive version first and mention KMP as the optimization.
When this pattern shows up
Any "find a substring / does B occur inside A / match a small pattern against a big string" question starts with this slide-and-compare template. Get the naive two-pointer version right, then name KMP or Rabin-Karp if the interviewer pushes for the linear-time answer.
Watch the bounds. Loop i only up to n - m (use range(n - m + 1)), and the j < m guard must come
before text[i + j] == pattern[j] so short-circuit evaluation stops you from indexing past the
pattern. An empty pattern should return 0, which this code already does.
Practice
For text = 'abaacaab', pattern = 'aab', at start i = 2 the first two characters match. Which character causes the mismatch, and what happens next?
1. What is the worst-case time complexity of the naive strStr?
2. What does the index j represent in the inner loop?
3. Why must the check j < m come before text[i + j] == pattern[j]?
4. What does KMP improve over this naive approach?