KMP串的模式匹配(mooc笔记)

什么是串?

线性存储的一组数据(默认是字符)

串的模式匹配即在串中寻找给定子串,要实现这点一个简单的方法是调用相关的库函数,比如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;  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值