题目:
经典的KMP算法
分析:
和KMP算法对应的是BF算法,其中BF算法时间复杂度,最坏情况下可以达到O(n*m),而KMP算法的时间复杂度是O(n + m),所以,KMP算法效率高很多。
但是KMP算法不太好理解,其中牵涉到next数组,目标就是让模式串尽可能的往右滑动,减少比较次数,比如
a b a b c
-1 0 0 1 2
比如我们比较ababc时,如果c比较发现错误,前面的abab已经比较成功,那么下次比较,我们只需要从aba的最后一个a开始比较,这样省去了从头开始比较。
算法代码:
#include <iostream>
#include <cstdlib>
#include <cstdio>
using namespace std;
//这是整个kmp中最核心的地方
int get_next(const char*t, int *next)
{
int i = 0;
int j = -1; //设置j = -1,非常巧妙
int len = strlen(t);
memset(next,0, sizeof(int) * len);
next[0] = -1;
while(i < len - 1)
{
if(j == -1 || t[i] == t[j]) //前面的判断,j == -1, 非常巧妙
{
i++;
j++;
next[i] = j; //将后面的next数组元素赋值
}
else
j = next[j];
}
}
int kmp(const char *s, const char *t)
{
int i = 0;
int j = 0;
int next[100];
get_next(t,next);
while(i < strlen(s) && j < strlen(t))
{
if(j == - 1 || s[i] == t[j]) //如果j为-1,或者模式串和主串相等,两者继续往下比较
{
i++;
j++;
}
else
j = next[j];
}
if(j >= (int)strlen(t))
{
cout << "found " << endl;
return 0;
}
cout << "not found" <<endl;
return 0;
}
//暴力法
int brute_force(const char *s, const char *t)
{
int i, j;
i = 0;
while(i < strlen(s))
{
j = 0;
while(j < strlen(t))
{
if(s[i] == t[j])
{
i++;
j++;
}
else
{
i = i - j + 1;
break;
}
}
if(j == (int)strlen(t))
{
cout << "found" << endl;
return 0;
}
}
cout << "not found" << endl;
return 0;
}
int main()
{
brute_force("abcdef", "abcdef");
kmp("abcdef", "aaaa");
return 0;
}
总结:
KMP算法非常经典,同时这个算法实现很多地方非常巧妙。