模式匹配
BF算法
暴力解
1.两串的起始下标为0
2.循环结束的条件:子串遇到\0→成功返回位置,主串遇到\0(长度减子串长度的位置) →失败
3.比较:s = t,下一位; s != t 回溯
4.回溯:s的指针i回到主串i-j+1 位置 j回到子串头部
时间复杂度
S长度:n T长度:m
最好情况:不成功的匹配都发生在T的第一个字符
不成功趟数的比较次数----1*(i-1)次
成功趟数的比较次数----m次
所有匹配成功的可能情况有n-m+1
(n+m)/2
O(n+m)
最差情况:不成功的匹配都发生在T的最后一个字符
不成功趟数的比较次数----m*(i-1)次
成功趟数的比较次数----m次
一共比较了i*n次
m(n-m+2)/2
O(n*m)
KMP算法
KMP改进了BF的回溯算法,利用了已经部分匹配的结果,主串中的i不回溯,只是子串滑动,省去了没必要的回溯,大大提高了效率。
分清:前缀后缀 前缀后缀相当于一个“标识”
T移动位数 = 子串已匹配的字符数 - 失配位置前的最长前缀匹配字符数
j对齐位置:失配位置前的最长前缀匹配字符数+1 - 1(+1是前缀的后一位 -1是数组从0存储)
next数组的三种取值
- 当j = 0时, next[j]=-1 不进行字符比较 此时要做i++ j++ (同前面比较:s[] = t[]的情况)
- 当j > 0 时, next[j]的值为:前缀后缀相同的长度
- 当前缀后缀相同的长度为0时,next[j]=0 回到头部开始比较
Next数组
next数组的获取极难理解
建议边看void getNext(char* T, int* n)边完成以下表格:
ij位置 | j起始位置 | i起始位置 | ||||||
---|---|---|---|---|---|---|---|---|
ij对应的值 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
T串 | 无 | a | b | c | d | a | b | d |
next数组 | 无 | -1起始值 |
void getNext(char* T, int* n)//只对子串T进行处理
{
int lenT = strlen(T);
int j = -1;//j是前缀
int i = 0;//i是后缀
n[0] = -1;//next数组
while (i < lenT)//i在T内
{
if (j == -1 || T[i] == T[j])