给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
示例 1:
1 2 3 4
| 输入:haystack = "sadbutsad", needle = "sad" 输出:0 解释:"sad" 在下标 0 和 6 处匹配。 第一个匹配项的下标是 0 ,所以返回 0 。
|
示例 2:
1 2 3
| 输入:haystack = "leetcode", needle = "leeto" 输出:-1 解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。
|
提示:
1 <= haystack.length, needle.length <= 104
haystack
和 needle
仅由小写英文字符组成
双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution { public int strStr(String haystack, String needle) { int left = 0; int right = 0; int i = 0; while(right < haystack.length()){ if(haystack.charAt(right) == needle.charAt(i)){ right ++; i ++; if(i == needle.length()){ return left; } }else{ left ++; right = left; i = 0; } } return -1; }
}
|
时间复杂度:n
为原串的长度,m
为匹配串的长度。复杂度为 O(m*n)。
KMP算法
使用next数组记录最长相同的前后缀
next[i]表示下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。
前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串。
后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
以字符串aabaaf为例
next数组为{0,1,0,1,2,0}
当模式串不匹配时,例如匹配到f匹配不成功,只需要找到f前面的字符串的最长相同前后缀,”aabaa”的最长相同前后缀为
2,即next[4] = 2,此时只需要用b和主串比较即可。因为f之前的”aabaa”都与主串匹配,而“aa”是最长的相同前后缀,不需要再进行重复的比较。
构造next数组
构造next数组的过程与匹配的过程相似
next[0] = 0,因为长度为1的串不存在最长相同前后缀
用 i 表示最长相同前后缀的长度,同时 i 也表示最长相同前缀尾部的下一个下标
j表示最长相同后缀尾部的下一个下标
即 i 从0开始遍历,j 从1开始遍历
如果s[ i ] == s[ j ] ,则 i++ ,表示最长相同前缀+1
否则 i = next[ i-1 ], i 回退到上一次匹配的位置,相当于将 i 指针看作模式串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Solution { public int strStr(String text, String needle) { int[] next = getNext(needle);
int j = 0; for(int i = 0; i < text.length(); i++){ while(j > 0 && text.charAt(i) != needle.charAt(j)){ j = next[j-1]; } if(text.charAt(i) == needle.charAt(j)){ j++; } if(j == needle.length()){ return i - needle.length() + 1; } } return -1; }
public int[] getNext(String s){ int[] next = new int[s.length()]; int i = 0; int j = 1; next[0] = i; while(j < s.length()){ if(i > 0 && s.charAt(i) != s.charAt(j)){ i = next[i-1]; } if(s.charAt(i) == s.charAt(j)){ i++; } next[j] = i; j++; } return next; } }
|
- 时间复杂度:
n
为原串的长度,m
为匹配串的长度。复杂度为 O(m+n)。