kmp例题

next数组的性质:

性质:如果len%(len-next[len])==0,则字符串中必存在最小循环节,且循环次数即为len/(len-next[len]);

证明:在前len个字符组成的字符串,存在最小循环节k,那么next[len]=len-k;(为什么呐?因为next数组的定义就是最大前后缀相同的子串的长度,len的总长度减去最小循环节,比如有3个循环节,减去一个剩下两个,就是最大循环节)那么循环次数就是len/(len-next[len]);因为len-next[len]=k;所以得出公式;

(此段引用自:https://www.cnblogs.com/wuwangchuxin0924/p/5977503.html

hdu2087

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087

题意:求str1中有多少个str2.

题解:

       这题数据很水,不用kmp也能过。(其实是因为之前kmp写错了)

       用kmp的话,就是一般kmp的做法在str2匹配完后就他跳出循环,这时候把跳出循环改成str2从头继续匹配即可。

#include <bits/stdc++.h>
using namespace std;

const int inf = 0x3f3f3f3f;
const int maxn = 2005;
#define eps 1e-8
#define INIT(x) memset(x,0,sizeof(x))
typedef long long ll;

string s2,s1;
int nxt[maxn];

void get_next(string s)
{
    nxt[0] = -1;
    nxt[1] = 0;
    int cn = 0;
    int i = 2;
    while(i<s.length())
    {
        if(s[i-1]==s[cn])
            nxt[i++] = ++cn;
        else if(cn>0)
            cn = nxt[cn];
        else
            nxt[i++] = 0;
    }
}

int kmp()
{
    INIT(nxt);
    int ans = 0;
    get_next(s2);
    int i=0,j=0;
    while(i<s1.length()&&j<s2.length())
    {
        if(s1[i]==s2[j]) {
            i++,j++;
        }else if(nxt[j]==-1) {
            i++;
        }else {
            j = nxt[j];
        }
        if(j==s2.length()) {
            ans++;
            j = 0;
        }
    }
    return ans;
}

int main()
{
    while(cin>>s1)
    {
        if(s1[0]=='#') break;
        cin>>s2;
        int ans = kmp();
        cout<<ans<<endl;
    }
    return 0;
}

poj2752

题目链接:http://poj.org/problem?id=2752

题意:

       给一个字符串s,要求s中寻找子串,使得子串既是原串的前缀也是原串的后缀。求满足条件的子串,并其次输出它们。

题解:

      根据题意,至少有一个子串,就是s本身。

      其余的根据next数组的性质,求的就是公共的前后缀,所以利用next数组的性质可以比较轻松的求出来。

      举个例子,abababab,在位置9(从0开始)的next数组值为6,那么6就是题目的一个解;

                                           在位置6的值为4,那么4也是其的一个解。这是因为开头的值不会变,而最后位置的值和next数组对应位置的值必然相等得到的。

       所以,结果就是next[m],next[next[m]]这样递推下去。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

const int inf = 0x3f3f3f3f;
const int maxn = 400005;
#define eps 1e-8
#define INIT(x) memset(x,0,sizeof(x))
typedef long long ll;

string s;
int nxt[maxn];
vector<int> e;

void get_next(string s)
{
    nxt[0] = -1;
    nxt[1] = 0;
    int i = 2;
    int cn = 0;
    while(i<=s.length())
    {
        if(s[i-1]==s[cn])
            nxt[i++] = ++cn;
        else if(cn>0)
            cn = nxt[cn];
        else
            nxt[i++] = 0;
    }
}

int main()
{
    while(cin>>s)
    {
        INIT(nxt);
        e.clear();
        get_next(s);
        int m = s.length();
        while(m)// m必然大于等于0,因为它相当于字符串s2的长度
        {
            e.push_back(m);
            m = nxt[m];
        }
        for(int i=e.size()-1;i>0;i--)
            cout<<e[i]<<" ";
        cout<<e[0]<<endl;
    }
    return 0;
}

poj2406 最小循环节

题目链接:http://poj.org/problem?id=2406

题意:

       给一个字符串s,求一个字符串a,使得s是由a重复k次构成的,令k尽量大,求出这个a。

题解:

       这题就是最小循环节问题。

       首先我们来看ababab这个字符串,next[6] = 4, 所以5,6位置必然和3,4位置相等,根据next数组的递推原则,next[4] = 2,所以3,4位置和1,2位置相等,因此我们可以推出。如果next[m] = x, m%(m-x)==0, 那么最有解一定就是m-x开始的那部分字符串。

      可以看开头的next数组的性质。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

const int inf = 0x3f3f3f3f;
const int maxn = 1000005;
#define eps 1e-8
#define INIT(x) memset(x,0,sizeof(x))
typedef long long ll;

string s;
int nxt[maxn];
vector<int> e;

void get_next(string s)
{
    nxt[0] = -1;
    nxt[1] = 0;
    int i = 2;
    int cn = 0;
    while(i<=s.length())
    {
        if(s[i-1]==s[cn])
            nxt[i++] = ++cn;
        else if(cn>0)
            cn = nxt[cn];
        else
            nxt[i++] = 0;
    }
}

int main()
{
    while(cin>>s)
    {
        if(s[0]=='.')
            break;
        INIT(nxt);
        get_next(s);
        int m = s.length();
        int x = nxt[m];
        int ans = 0;
        while(~x)
        {
            if(m%(m-x)==0) {
                ans = m-x;
                break;
            }
            x = nxt[x];
        }
        cout<<m/ans<<endl;
    }
    return 0;
}

 

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/zxwsbg/article/details/81630537
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞