- Interview Questions
- /
- Problems
- /
- Find the Index of the First Occurrence in a String
Find the Index of the First Occurrence in a String
Return where a pattern first appears inside a longer string, or -1 if it never does. A gateway to string matching, from the direct scan to linear-time KMP. Solve it below in Python or JavaScript, then read the walkthrough.
Problem
You're given two strings, haystack and needle. Return the index in haystack where the first occurrence of needle begins, or -1 if needle does not appear in haystack at all.
An occurrence means needle matches a run of consecutive characters in haystack exactly. If needle appears several times, return the smallest starting index.
Example 1
- Input
- haystack = "banana", needle = "ana"
- Output
- 1
"ana" starts at index 1 and again at index 3. The first one wins.
Example 2
- Input
- haystack = "rocket", needle = "rock"
- Output
- 0
Example 3
- Input
- haystack = "planet", needle = "plane t"
- Output
- -1
The needle is longer than the haystack, so it cannot appear.
Example 4
- Input
- haystack = "aabaab", needle = "abb"
- Output
- -1
Constraints
- 1 ≤ haystack.length, needle.length ≤ 10⁴
- Both strings contain only lowercase English letters and spaces.
- needle may be longer than haystack.
Practice
Runs 14 tests in your browser. Python loads on the first run (about 6 MB, then cached). Press ⌘/Ctrl + Enter to run.
Get asked Find the Index of the First Occurrence in a String in a real interview?
Interview Solver gives you a working solution live, during your actual coding interview. Invisible to screensharing.
How to solve Find the Index of the First Occurrence in a String
Pattern: String matching with a prefix function (KMP)
The direct idea is to try every start position and compare character by character. That is fine for typical text, but it repeats work on inputs like "aaaa...ab": after matching 999 characters and failing on the last, it moves one position right and re-checks almost the same 999 characters.
KMP avoids that by precomputing, for each prefix of the needle, the length of its longest proper prefix that is also a suffix. When a mismatch happens after matching j characters, you already know the last j haystack characters equal needle[0..j), so you can fall back to that border length instead of starting over. The haystack pointer never moves backward, which makes the whole search linear.
Approach 1: Check every start position
For each i from 0 to n - m, compare haystack[i..i+m) with needle and return the first match. Simple and often fast enough in practice, but it degrades on repetitive inputs with many near misses.
Time O(n · m) · Space O(1)
Approach 2: Rolling hash (Rabin-Karp)
Hash the needle and every window of the same length, updating the window hash in O(1) as it slides. Only compare characters when the hashes match. Expected linear time, but a weak hash or adversarial input can cause false positives that cost extra comparisons.
Time O(n + m) expected · Space O(1)
Approach 3: Knuth-Morris-Pratt
- Build
lps, wherelps[k]is the length of the longest proper prefix ofneedle[0..k]that is also its suffix. - Scan the haystack with
j= number of needle characters matched so far. On a match, advancej; ifj == m, returni - m + 1. - On a mismatch with
j > 0, setj = lps[j - 1]and retry the same haystack character; ifj == 0, move on.
Time O(n + m) · Space O(m)
| Approach | Time | Space |
|---|---|---|
| Check every start position | O(n · m) | O(1) |
| Rolling hash (Rabin-Karp) | O(n + m) expected | O(1) |
| Knuth-Morris-Pratt | O(n + m) | O(m) |
Solution code
Try the practice editor first. Both solutions pass every test above.
Find the Index of the First Occurrence in a String solution in Python
def str_str(haystack: str, needle: str) -> int:
m = len(needle)
# lps[k]: longest proper prefix of needle[:k+1] that is also a suffix of it
lps = [0] * m
length = 0
for k in range(1, m):
while length and needle[k] != needle[length]:
length = lps[length - 1]
if needle[k] == needle[length]:
length += 1
lps[k] = length
j = 0
for i, ch in enumerate(haystack):
while j and ch != needle[j]:
j = lps[j - 1]
if ch == needle[j]:
j += 1
if j == m:
return i - m + 1
return -1Find the Index of the First Occurrence in a String solution in JavaScript
function strStr(haystack, needle) {
const m = needle.length;
// lps[k]: longest proper prefix of needle[0..k] that is also a suffix of it
const lps = new Array(m).fill(0);
let length = 0;
for (let k = 1; k < m; k++) {
while (length > 0 && needle[k] !== needle[length]) length = lps[length - 1];
if (needle[k] === needle[length]) length++;
lps[k] = length;
}
let j = 0;
for (let i = 0; i < haystack.length; i++) {
while (j > 0 && haystack[i] !== needle[j]) j = lps[j - 1];
if (haystack[i] === needle[j]) {
j++;
if (j === m) return i - m + 1;
}
}
return -1;
}Common mistakes
- Looping the start index all the way to `n - 1` and reading past the end of the haystack, or stopping at `n - m - 1` and missing a match at the very end.
- Forgetting the case where the needle is longer than the haystack.
- In KMP, advancing the haystack pointer after a fallback instead of retrying the same character against the shorter prefix.
- Building the `lps` table with `lps[j]` instead of `lps[j - 1]` on a mismatch, which is an off-by-one that loops forever or skips matches.
What interviewers look for
Most interviewers are happy with the O(n · m) scan if you write it cleanly and say where its worst case comes from. Mention that built-ins like find or indexOf exist, but don't use them unless they say it's allowed.
If they push for better, explain the lps idea in words first: "on a mismatch I already know what the last j characters were, so I can reuse the longest border instead of rescanning." Then write the table builder and the scan, which share the same fallback loop.
Follow-up questions
How would you return every occurrence instead of the first?
In KMP, when `j == m`, record `i - m + 1` and set `j = lps[m - 1]` to keep scanning. This finds overlapping matches too and stays O(n + m).
How would you search for many needles at once?
Build an Aho-Corasick automaton: a trie of all needles plus failure links that generalize the `lps` table. One pass over the haystack reports every match of every needle.
When is Rabin-Karp a better choice than KMP?
When matching many patterns of the same length, or finding repeated substrings of a given length, because you can put all window hashes in a set. It also extends naturally to 2D pattern matching.
Companies that ask Find the Index of the First Occurrence in a String
Find the Index of the First Occurrence in a String is tagged by 111 companies in our interview dataset. The score shows how often it comes up at each company.
- Nisum100%
- Siriusxm100%
- Podium100%
- Gojek Tech100%
- Sisense100%
- Pocket Gems100%
- Draftkings97%
- Albertsons96%
- Hackerrank91%
- Sourcegraph89%
- Gemini88%
- SpaceX88%
- Cargurus87%
- C3.ai85%
- Bonterra84%
- Crispr Therapeutics82%
- TSMC82%
- Browserstack81%
- Lacework80%
- Motional80%
- Angi79%
- Airtasker78%
- Genesys78%
- Chainalysis78%
and 87 more.
Practice next
Get live help in the real interview
Working solutions in real time during your actual interview. Invisible to screensharing.
Start Free TrialNo credit card required