什么是串?
线性存储的一组数据(默认是字符)
串的模式匹配即在串中寻找给定子串,要实现这点一个简单的方法是调用相关的库函数,比如c语言的strstr函数,它的实现方式是逐个字符匹配,例如在string = "abcabd"中匹配pattern = “abd”,遇到’a’开始匹配,当匹配到’c’的时候发现匹配不上,就退到第二个字符开始,所以这种匹配方法的时间复杂度为O(nm),其中n为string的长度,m为pattern的长度
大师改进(KMP算法)
时间复杂度:T = O(n + m)
特点:利用了已经匹配上的串,减少了多余的操作,为了利用这个特点,需要先对模式串pattern进行分析,借助match函数可以一次位移多个字符
因此需要根据以上规则建立一个match数组:match[i]的值为当前位置到第一个位置的子串中非空的既是前缀又是后缀的字符串的前缀的最后一个字符所在下标,两个字符串可以相交,如match[6]中abca为最长的满足条件的字符串
对与第一个字符来说match值一定为-1,因此初始化数组的时候可以将match[0] = -1
BuildMatch的实现
假设已经得到了j-1的match值,对于j,我们直接与match[j-1]的下一个字符比较,如果相等,则match[j] = match[j - 1] + 1,如果不相等就与match[match[j - 1]] + 1位置的字符比对,以此内推,可以理解为一个循环的过程,也可以理解为一个递归的过程
代码实现
void BuildMatch(char *pattern, int *match){
int i, j;
int m = strlen(pattern); // T = O(m)
match[0] = -1;
for(j = 1; j < m; j++){ // T = O(m)
i = match[j - 1];
while(i >= 0 && pattern[j] != pattern[i + 1]) //执行总次数不会超过m
i = match[i];
if(pattern[j] == pattern[i + 1]) //得到match值
match[j] = i + 1;
else match[j] = -1; //没有匹配的字符串
}
}
因此T = O(m)
相关练习LeetCode1392.最长快乐前缀](https://leetcode-cn.com/problems/longest-happy-prefix/)
KMP算法实现
代码如下
int KMP(char *string, char *pattern){
int n = strlen(string);
int m = strlen(pattern);
int s, p, *match;
if(n < m) return -1;
match = (int *)calloc(m, sizeof(int));
BuildMatch(pattern, match);
s = p = 0;
while(s < n && p < m){
if ( string[s]==pattern[p] )
s++,p++;
else if (p>0) p = match[p-1]+1;
else s++;
}
return p == m ? s - m : -1;
}
完整代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int Position;
#define NotFound -1
void BuildMatch( char *pattern, int *match )
{
Position i, j;
int m = strlen(pattern);
match[0] = -1;
for ( j=1; j<m; j++ ) {
i = match[j-1];
while ( (i>=0) && (pattern[i+1]!=pattern[j]) )
i = match[i];
if ( pattern[i+1]==pattern[j] )
match[j] = i+1;
else match[j] = -1;
}
}
Position KMP( char *string, char *pattern )
{
int n = strlen(string);
int m = strlen(pattern);
Position s, p, *match;
if ( n < m ) return NotFound;
match = (Position *)malloc(sizeof(Position) * m);
BuildMatch(pattern, match);
s = p = 0;
while ( s<n && p<m ) {
if ( string[s]==pattern[p] ) {
s++; p++;
}
else if (p>0) p = match[p-1]+1;
else s++;
}
return ( p==m )? (s-m) : NotFound;
}
int main()
{
char string[] = "This is a simple example.";
char pattern[] = "simple";
Position p = KMP(string, pattern);
if (p==NotFound) printf("Not Found.\n");
else printf("%s\n", string+p);
return 0;
}