码迷,mamicode.com
首页 > 编程语言 > 详细

KMP 算法总结

时间:2015-10-29 21:42:22      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:

KMP算法是基本的字符串匹配算法,但是代码实现上有一些细节容易错。这篇随笔将认真总结一下。

KMP算法的核心是:

The KMP algorithm searches for occurrences of a "word" W within a main "text string" S by employing the observation that when a mismatch occurs, the word itself embodies sufficient information to determine where the next match could begin, thus bypassing re-examination of previously matched characters. (form Wikipedia)

首先定义一个概念

给定字符串s[0..L-1], 若存在s的某个正规前缀(proper prefix) s[0..i] (i<L-1) 也是s的后缀,则将此前缀称作关键前缀(critical prefix)

显然空串是任意非空串的关键前缀。

对于模式串w, 预处理一个长为|w|的数组next[0..|w|-1],nt[i]表示w的前缀的w[0..i]的最长关键前缀的长度。

借助next[]数组,可以在O(|s|)时间内完成搜索。

具体实现以及复杂度分析略过,留下K. M. P. 三人论文的链接

 Knuth, Donald; Morris, James H.; Pratt, Vaughan (1977). "Fast pattern matching in strings"SIAM Journal on Computing 6 (2): 323–350.doi:10.1137/0206024.

------------------------------------------------------------

题目链接:hihocoder 1015

#include <bits/stdc++.h>
using namespace std;
const int N(1e4+5), M(1e6+5);
char s[N], t[M];
int nt[N];
int main(){
    int n;
    scanf("%d", &n);
    for(int ls, k, ans;n--;){
        scanf("%s%s", s, t);
        k=nt[0]=0;
        for(int i=ls=1; s[i]; i++, ls++){
            for(;k&&s[k]!=s[i];) k=nt[k];  
            nt[i]=s[i]==s[k]?++k:k;
        }
        ans=k=0;
        for(int i=0; t[i]; i++){
            //k:t[0..i-1]的匹配长度
            for(;k&&s[k]!=t[i];) k=nt[k-1];     //error-prone
            if(t[i]==s[k]){
                k++;
                if(k==ls) ans++;
            }
        }
        printf("%d\n", ans);
    }
}

 

代码中注释的两处是容易写错的地方,典型错误是

for(;k&&s[k]!=s[i];) k=nt[k];
for(;k&&s[k]!=t[i];) k=nt[k]; 

这个错误坑在:往往可过样例,提交后不会WA而是会TLE。

----------------------

还可以将next[i]定义成前缀w[0..i]的最长关键前缀的长度减一,这时可将next[i]的含义改成前缀w[0..i]的最长关键前缀的结束位置。

代码只消稍作变动

#include<bits/stdc++.h>
using namespace std;
const int MAX_N=1e6+10;
char s[MAX_N], t[MAX_N];
int nt[MAX_N];
void get_next(char *s){
    nt[0]=-1;
    int k=-1;
    for(int i=1; s[i]; i++){
        while(k!=-1&&s[k+1]!=s[i]) k=nt[k];
        if(s[k+1]==s[i]) k++;
        nt[i]=k;
    }
}

int ans;
void match(char *s, char *t){
    int ls=strlen(s), k=-1;
    for(int i=0; t[i]; i++){
        while(k!=-1&&s[k+1]!=t[i]) k=nt[k];
        if(s[k+1]==t[i]) k++;
        if(k==ls-1) ans++;
    }
}
int main(){
    int N;
    scanf("%d", &N);
    while(N--){
        scanf("%s%s", s, t);
        get_next(s);
        ans=0;
        match(s, t);
        printf("%d\n", ans);
    }
    return 0;
}

 

KMP 算法总结

标签:

原文地址:http://www.cnblogs.com/Patt/p/4921628.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!