摘要:
Leetcode的AC指南 —— 字符串/KMP:28.找出字符串中第一个匹配项的下标。题目介绍:给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。
一、题目
题目介绍:给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。
力扣题目链接
示例 1:
输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。
示例 2:
输入:haystack = "leetcode", needle = "leeto"
输出:-1
解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。
提示:
1 <= haystack.length, needle.length <= 104
haystack 和 needle 仅由小写英文字符组成
二、解析(go)
1、一个简单的AC方法
思路:让needle在haystack中滑动
go:
func strStr(haystack string, needle string) int {
runes := []byte(haystack)
for i := 0; i <= len(haystack)-len(needle); i++ {
if string(runes[i:len(needle)+i]) == needle {
return i
}
}
return -1
}
- 时间复杂度O(n-m)
- 空间复杂度O(n)
2、KMP算法:直接使用前缀表作为next数组
思路:
-
构造next数组文章来源:https://www.toymoban.com/news/detail-782994.html
- 初始化:前缀末尾指针before指向第一个字符,第一个子串的前后缀长度next[0]为0
- 默认before指针之前的字符与behind指针之前的字符相等。
- 比较before指向的字符与behind指向的字符是否相等。
- 当不相同时,before指向前一个字符,重新比较,直到before指向第一个字符或者before与behind的字符相等时,结束比较。
- 当又相同时,before指向下一个字符。
- before的位置就是最长前后缀长度,更新next数组。
-
使用next数组做匹配文章来源地址https://www.toymoban.com/news/detail-782994.html
- 初始化
- i为文本串起始位置,j为模式串起始位置
- 得到next数组
- 在文本串中查找模式串,对比i和j分别对应的字符
- 若i和j相等,则i和j同时后移
- 若i和j不相等,则j寻找之前匹配的位置,
- 也就是通过next数组的最大相同子串长度滑动j,确定从模式串的哪个位置开始重新比较
- 当 j 比完模式串的最后一个字符后,说明模式串在文本串中出现过,返回结果
- 若文本串遍历结束,j也没有指向模式串的最后一个字符,就返回-1
- 初始化
//直接将前缀表作为next数组
func getnext(next []int, s string) {
// before: 前缀末尾,前缀长度
// behand:后缀末尾
before := 0
next[0] = 0
for behind := 1; behind < len(s); behind++ {
for before > 0 && s[behind] != s[before] { // 前缀与后缀不相等
before = next[befor-1]
}
if s[behind] == s[before] { // 前缀与后缀相等
before++
}
next[behind] = before
}
}
// 直接将前缀表作为next数组的匹配实现
func strStr(haystack string, needle string) int {
j := 0 // j 为模式串的起始位置, next数组记录的起始位置为0
next := make([]int, len(needle))
getnext(next, needle)
for i := 0; i < len(haystack); i++ { // i从0开始
for j > 0 && haystack[i] != needle[j] { // 不匹配
j = next[j-1] // j寻找之前匹配的位置
}
if haystack[i] == needle[j] { // 匹配,j 和 i同时向后移动
j++ // i的增加在for循环中
}
if j == len(needle) { // 文本串haystack中出现了模式串needle
return i - j + 1
}
}
return -1
}
- n为文本串长度,m为模式串长度。
- 匹配的过程是O(n),
- 单独生成next数组,时间复杂度是O(m)。
- 整个KMP算法的时间复杂度是O(n+m)的。
三、其他语言版本
Java
class Solution {
//前缀表(不减一)Java实现
public int strStr(String haystack, String needle) {
if (needle.length() == 0) return 0;
int[] next = new int[needle.length()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.length(); i++) {
while (j > 0 && needle.charAt(j) != haystack.charAt(i))
j = next[j - 1];
if (needle.charAt(j) == haystack.charAt(i))
j++;
if (j == needle.length())
return i - needle.length() + 1;
}
return -1;
}
private void getNext(int[] next, String s) {
int j = 0;
next[0] = 0;
for (int i = 1; i < s.length(); i++) {
while (j > 0 && s.charAt(j) != s.charAt(i))
j = next[j - 1];
if (s.charAt(j) == s.charAt(i))
j++;
next[i] = j;
}
}
}
C++
class Solution {
public:
void getNext(int* next, const string& s) {
int j = 0;
next[0] = 0;
for(int i = 1; i < s.size(); i++) {
while (j > 0 && s[i] != s[j]) {
j = next[j - 1];
}
if (s[i] == s[j]) {
j++;
}
next[i] = j;
}
}
int strStr(string haystack, string needle) {
if (needle.size() == 0) {
return 0;
}
int next[needle.size()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.size(); i++) {
while(j > 0 && haystack[i] != needle[j]) {
j = next[j - 1];
}
if (haystack[i] == needle[j]) {
j++;
}
if (j == needle.size() ) {
return (i - needle.size() + 1);
}
}
return -1;
}
};
Python
class Solution:
def getNext(self, next: List[int], s: str) -> None:
j = 0
next[0] = 0
for i in range(1, len(s)):
while j > 0 and s[i] != s[j]:
j = next[j - 1]
if s[i] == s[j]:
j += 1
next[i] = j
def strStr(self, haystack: str, needle: str) -> int:
if len(needle) == 0:
return 0
next = [0] * len(needle)
self.getNext(next, needle)
j = 0
for i in range(len(haystack)):
while j > 0 and haystack[i] != needle[j]:
j = next[j - 1]
if haystack[i] == needle[j]:
j += 1
if j == len(needle):
return i - len(needle) + 1
return -1
到了这里,关于Leetcode的AC指南 —— 字符串/KMP:28.找出字符串中第一个匹配项的下标的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!