KMP模版 && KMP求子串在主串出现的次数模版

求取出现的次数 : 

#include<bits/stdc++.h>
const int maxn = 1e6 + 10;
char mo[maxn], str[maxn];///mo为模式串、str为主串
int next[maxn];
inline void GetNext()
{
    int i = 0, j = -1, len = strlen(mo);
    next[i] = j;
    while(i < len){
//        if(j == -1 || mo[i] == mo[j]) next[++i] = ++j;
//        else j = next[j];
        while( j != -1 && mo[i] != mo[j]) j = next[j];
        next[++i] = ++j;
    }
}
int KmpCount()///计算模式串在子串出现的次数
{
    GetNext();
    int i = 0, j = 0, strL = strlen(str), moL = strlen(mo);
    int ans = 0;
    while(i < strL){
        while( j != -1 && mo[j] != str[i]) j = next[j];
        i++, j++;
        if(j == moL) ans++;
    }
    return ans;///返回模式串在主串中出现的次数(可重叠出现)
}
int main(void)
{
    scanf("%s %s", str, mo);
    printf("%d\n", KmpCount());
    return 0;
}
View Code

 

求模式串第一次在主串出现的位置 or 匹配是否在主串出现过 :

#include<bits/stdc++.h>
const int maxn = 1e6 + 10;
char mo[maxn], str[maxn];///mo为模式串、str为主串
int next[maxn];
inline void GetNext()
{
    int i = 0, j = -1, len = strlen(mo);
    next[i] = j;
    while(i < len){
        while( j != -1 && mo[i] != mo[j]) j = next[j];
        next[++i] = ++j;
    }
}
int KmpIndex()
{
    GetNext();
    int i =0, j = 0, strL = strlen(str), moL = strlen(mo);
    while(i < strL && j < moL){
        while( j != -1 && str[i] != mo[j]) j = next[j];
        i++, j++;
    }
    if(j == moL) return i - moL;///返回模式串在主串中首次出现的位置
    else return -1;
}
int main(void)
{
    scanf("%s %s", str, mo);
    printf("%d\n", KmpIndex());
    return 0;
}
View Code

 

 

///--------------------------------------------------------------------------------------------------------------------------

 

KMP算法的解释尤其是next数组可以参考这个博客 : http://blog.csdn.net/yutianzuijin/article/details/11954939/ 

这个是我对KMP的next数组的一点理解,都写在注释里面了

#include<bits/stdc++.h>
const int maxn = 1e6 + 10;
char mo[maxn], str[maxn];///分别为模式串和子串
int next[maxn];
/// next[i] 可以"翻译"成 i 这里失配了,考虑 0~(i-1) 这个
/// 串,看能否找到一个位置 k 和 k' 使得前缀 0~k 和后缀 
/// k'~(i-1)一样,而next[i]存储的就是 k+1 这个位置,即
/// 前缀的前一个
inline void GetNext()
{
    int i = 0, j = -1, len = strlen(mo);
    next[i] = j;
    while(i < len){
        while( j != -1 && mo[i] != mo[j]) j = next[j];
        next[++i] = ++j;
    }
}
///-------------------------------------------------------------
///可以用下面的图来动态演示一下GetNext()的步骤,可能就能够理解
//                  i              
//- 0 1 2 3 4 5 6 7 8
//  a b c a b c a d x
//  - 0 0 0 1 2 3 4 0           
//                  a b c a b c a d x 
//                  - 0 0 0 1 2 3 4 0          
//                  j
///下面有几句话可能能帮助理解
///①找next的值相当于就是拿模式串自己和自己匹配,在下面移动的就是后缀,在上面的就是前缀
///②当前匹配的字符以及其前面的字符的next值肯定是已经求出来的
///③当j==-1的时候就说明现在的i连模式串的第一个都不能匹配到
///④如果是判断当前的 i 和 j 则说明是在为 i+1 这个字符寻找 0~i (即i+1后的字符串)是否拥有相同前后缀
///--------------------------------------------------------------
int KmpCount()
{
    GetNext();
    int i = 0, j = 0, strL = strlen(str), moL = strlen(mo);
    int ans = 0;
    while(i < strL){
        while( j != -1 && mo[j] != str[i]) j = next[j];///匹配的时候当 j == -1 的时候就已经是第
        i++, j++;                                      ///一个现在的主串 i 连模式串的第一个都不
        if(j == moL) ans++;                            ///能匹配,所以下面让 i++,因为 j == -1,
    }                                                  ///所以 j++ 后自然是子串第一个
    return ans;
}
View Code

 

posted @ 2017-05-20 21:01  qwerity  阅读(763)  评论(0编辑  收藏  举报