Description
28. Find the Index of the First Occurrence in a String
Given two strings needle and haystack, return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
Example 1:
Input: haystack = "sadbutsad", needle = "sad"
Output: 0
Explanation: "sad" occurs at index 0 and 6. The first occurrence is at index 0, so we return 0.
Example 2:
Input: haystack = "leetcode", needle = "leeto"
Output: -1
Explanation: "leeto" did not occur in "leetcode", so we return -1.
Constraints:
haystackandneedleconsist of only lowercase English characters.
Approach 1: Sliding Window / Substring Comparison ( Time, Space)
Intuition
Slide a window of length (length of needle) across haystack (length ). At each index from to , compare characters sequentially to see if it equals needle. Return on the first complete match.
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length();
int m = needle.length();
if (m > n) return -1;
for (int i = 0; i <= n - m; i++) {
int j = 0;
while (j < m && haystack.charAt(i + j) == needle.charAt(j)) {
j++;
}
if (j == m) return i;
}
return -1;
}
}
Complexity
- Time Complexity: worst-case (e.g.,
haystack = "aaaaa",needle = "aab"). - Space Complexity: auxiliary space.
Approach 2: Knuth-Morris-Pratt (KMP) Algorithm (Optimal — Time, Space)
Intuition
Avoid re-checking characters that have already been matched by precomputing the LPS (Longest Prefix Suffix) table for needle. When a mismatch occurs at needle[j], instead of resetting the search pointer in haystack back to i - j + 1, slide needle forward using j = lps[j - 1].
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length();
int m = needle.length();
if (m == 0) return 0;
if (m > n) return -1;
// Step 1: Precompute LPS array for needle
int[] lps = computeLPS(needle);
// Step 2: KMP search over haystack using Pattern 1 (if-else)
int i = 0; // Pointer for haystack
int j = 0; // Pointer for needle
while (i < n) {
if (haystack.charAt(i) == needle.charAt(j)) {
i++;
j++;
if (j == m) {
return i - m; // Match found at starting index i - m
}
} else {
if (j != 0) {
j = lps[j - 1]; // Fallback using LPS array
} else {
i++;
}
}
}
return -1;
}
private int[] computeLPS(String pattern) {
int m = pattern.length();
int[] lps = new int[m];
int len = 0;
int i = 1;
while (i < m) {
if (pattern.charAt(i) == pattern.charAt(len)) {
len++;
lps[i] = len;
i++;
} else {
if (len != 0) {
len = lps[len - 1];
} else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
}
Complexity
- Time Complexity: — Precomputing LPS takes time and matching over
haystacktakes time. - Space Complexity: — For the LPS lookup table of
needle.
Easy Memory Rule
“Slide a window of size
needle.length()for simple brute force, OR buildneedle’s LPS array with KMP to skip repeated work in linear time!”