目录
一、概念
KMP解释:从主串中查找子串,返回子串在主串中的位置。
eg:主串"adadacacbc",子串 "adac" ->2
代码解析:
(1)在主串中查找子串:
循环遍历,对主串和子串的字母逐个匹配:arr[i]-'0'得到当前下标的字母。
(2)如果前几个字母匹配,并不是完全匹配,如何继续查找:
如:主串"adadacacbc",子串 "adac",匹配前3个字母时一致,后面不匹配,但是直接从后面继续查找就不可能匹配成功了,必须返回前面查找,返回的位置是:当前主串下标-当前子串下标+1:i-j+1。
(3)终止循环的条件:
匹配成功:匹配到了子串的最后一个位置: brr[j] == '\0';
匹配不成功:查找主串到最后一个位置也没找到:arr[i] == '\0'
终止条件: brr[i] == '\0' &&arr[i] == '\0',必须要同时满足,因为如果只满足了一个,当子串已经被完全匹配了,而母串没到最后一个位置,就要进入死循环了。
也可以定义一个计数器count,每当匹配成功时count++,不成功置为0,如果count==子串长度退出循环。
二、C语言实现
int KMP(char* arr,int len,char* brr,int length)
{
/* for (int i = 0; i < len; i++)
{
if (arr[i] == brr[i])
{
count++;
if (count == length)
return i;
}
}*///这个思想错误,没有考虑到每次重新匹配时count都要置为0
int j=0, i=0;
while(arr[i] != '\0'&& brr[j] != '\0')
/*for ( i = 0; arr[i] != '\0'; )
{
for (j = 0; brr[i] != '\0'; )*/ //两个条件应该是同时满足的
{
if (arr[i] == brr[j])
{
i++, j++;
}
else {
i = i - j + 1;
j = 0;
}
}
return brr[j]=='\0'?i - j:-1;
/*下面方法就只是引入count的做法
int count = 0;
int i = 0; int j = 0;
while (arr[i] != '\0'&&brr[j] != '\0' )
{
if (arr[i] == brr[j])
{
count++;
i++; j++;
}
else {
i++;
i = i - j + 1;
j = 0;
count = 0;
}
if (count == length)
return i - j;
}
}*/
}
int main()
{
char arr[] = "adadacacbc";
char brr[] = "adac";
int len = strlen(arr);
int length = strlen(brr);
printf("%d",KMP(arr, len, brr, length));
return 0;
}
运行结果:
三、C++实现(leetcode)
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。
来源:力扣(LeetCode)
class Solution {
public:
int strStr(string haystack, string needle) {
int len1=haystack.size();//strlen(haystack);
int len2=needle.size();//strlen(needle);
//for(int i=0;i<len1&&i<len2;i++)
int i=0,j=0;
int len3=0;
while(haystack[i]!='\0' && needle[j]!='\0')
//while(len1--&&len2--)
{
if(len3==len2)
{
break;
}
if(haystack[i]==needle[j])
{
i++;
j++;
len3++;
}
else
{
//i++;
i=i-j+1;
j=0;
len3=0;
}
}
return needle[j]=='\0'?i-j:-1;
}
};
运行结果