pku 1961 http://poj.org/problem?id=1961

题意:

给定一个长度为n的字符串,求他的前缀且前缀满足本身为周期字符串。例:aabaabaab 长度为9 周期为3

思路:

kmp几乎忘干净了,开始学的时候也没有真正的理解,今天看了好长时间的getnext函数;我们在对字符串本身处理得到next函数时,

next[i]记录的就是s[1,next[i]] 与s[i - next[i] + 1,i]相同时的值,这里next[i]也表示了相同区间的长度,我们的坐标从0开始则只要(i + 1)%(i - next[i]) == 0就能满足该字符串前缀是周期字符串,i+1表示的是当前枚举到的字符串的长度,(i - next[i])表示的就是一个周期的字符长度了。

KMP算法题目:_iosKMP算法题目:_子串_02View Code
#include <cstdio>
#include <iostream>
#include <cstring>
#define maxn 1000004
using namespace std;

int next[maxn];

void GetNext(char *s)
{
    int len = strlen(s);
    int i,j;
    i = 0; j = -1;
    next[0] = -1;
    for (i = 1; i < len; ++i)
    {
        while (j > -1 && s[j + 1] != s[i])
        j = next[j];
        if (s[j + 1] == s[i]) ++j;
        next[i] = j;
    }
}
int main()
{
    int n,i;
    char s1[maxn];
    int cas = 1;
    while (~scanf("%d",&n))
    {
        if (!n) break;
        printf("Test case #%d\n",cas++);
        scanf("%s",s1);
        GetNext(s1);
        for (i = 0; i < n; ++i)
        {
            int d = (i + 1)%(i - next[i]);
            if (d == 0 && next[i] != -1)
            {
                printf("%d %d\n",i + 1,(i + 1)/(i - next[i]));
            }
        }
        printf("\n");
    }
    return 0;
}

 

pku 2406 http://poj.org/problem?id=2406

同上:类似的题目:

KMP算法题目:_iosKMP算法题目:_子串_02View Code
#include <cstdio>
#include <iostream>
#include <cstring>
#define maxn 1000004
using namespace std;

int next[maxn];

void GetNext(char *s,int len)
{
    int i = 0,j = -1;
    next[0] = -1;
    for (i = 1; i < len; ++i)
    {
        while (j > -1 && s[j + 1] != s[i]) j = next[j];

        if (s[j + 1] == s[i]) ++j;
        next[i] = j;
    }
}
int main()
{
    char s[maxn];
    int i;
    while (gets(s))
    {
        if (s[0] == '.') break;
        int len = strlen(s);
        if (len == 0)
        {
            puts("0");
            continue;
        }
        GetNext(s,len);
        if (len%(len - 1 - next[len - 1]) == 0)
        printf("%d\n",len/(len - 1 - next[len - 1]));
        else
        printf("1\n");

    }
}

 

pku 3461 Oulipo http://poj.org/problem?id=3461

提议:

给你两个字符串,w,t查看字符串w在t中出现的次数;

思路:

kmp模式匹配,关键是到那个查找到其为子串时继续查找。

KMP算法题目:_iosKMP算法题目:_子串_02View Code
#include <cstdio>
#include <iostream>
#include <cstring>
#define maxn 1000004
using namespace std;

int next[maxn];
char W[maxn],T[maxn];

void GetNext(char *s)
{
    int i = 0,j = -1;
    int len = strlen(s);
    next[0] = -1;
    for (i = 1; i < len; ++i)
    {
        while (j > -1 && s[j + 1] != s[i]) j = next[j];

        if (s[j + 1] == s[i]) ++j;
        next[i] = j;
    }
}
void kmp(char *s1,char *s2)//s1副串 s2主串
{
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    int i,j = -1;
    int ans = 0;
    for (i = 0; i < len2; ++i)
    {
        while (j > -1 && s1[j + 1] != s2[i]) j = next[j];
        if (s1[j + 1] == s2[i]) ++j;
        if (j == len1 - 1)//找到子串,后继续查找
        {
            ans++;
            j = next[j];
        }
    }
    printf("%d\n",ans);
}
int main()
{
    int n;
    while (~scanf("%d",&n))
    {
        scanf("%s%s",W,T);
        GetNext(W);
        kmp(W,T);
    }
    return 0;
}