KMP+循环节问题

HDU-3746

现在给你一个字符串,请问在该字符串末尾最少添加多少个字符,可以让这个字符串获得重复循环序列。

输入:第一行是一个整数 T ( 0 < T < = 100 ) T ( 0<T<=100 ) 代表测试数据的组数。之后 T T 行每行一个字符串,由小写字母组成,字符串的长度 3 < = L < = 100000 3<=L<=100000

输出:每组数据输出一行结果。

样例:

3
ppp
pip
machinelearning
0
1
15

思路:

循环节是指一段数据中重复的最小环。KMP不止要学会套模板匹配字符串,还要学到KMP算法的精髓——Next数组
(未经优化的) N e x t [ i ] Next[i] 指的 S [ 0 i 1 ] S[0:i-1] 最大共同前后缀长度(例如abcabcabc的共同前后缀为abcabc, abcabc为abc, abcabcabcabc为abc*3)
故一段字符串的循环节就是: N N e x t [ N ] N - Next[N]
将其记为len。若该字符串是循环字符串,则 N % l e n = = 0 N\%len==0 , 而循环节的个数为: N / l e n N/len
若不是,则 N e x t [ N ] = = 0 Next[N] == 0 (abcd)或者 N % l e n   ! =   0 N\%len\ !=\ 0

题解

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

int n;
char s[maxn];
int Next[maxm];

int getnext()
{
    Next[0] = -1;
    int i = 0, j = -1;
    while(i<n)
    {
        while(j!=-1 && s[i]!=s[j]) j = Next[j];
        Next[++i] = ++j;
    }
    int len = - Next[n] + n;
    if(Next[n]==0) return len; //没有循环部分,只能自身成为循环节
    else if(Next[n]%len==0) return 0; //已经是循环字符串
    else return len - Next[n] % len; //需要补齐
}


int main()
{
    int T;
    cin >> T;
    getchar();
    while(T--)
    {
        scanf("%s", s);
        n = strlen(s);
        cout << getnext() << endl;
    }
    return 0;
}

HDU-1385

给出一个字符串s(1为起始),问在[1, i]区间是否有完整的循环节,若有,输出i并输出循环次数

3
aaa
12
aabaabaabaab
0
Test case #1
2 2
3 3

Test case #2
2 2      --aa(a)
6 2      --aabaab(aab)
9 3      --aabaabaab(aab)
12 4     --....

思路:求出Next数组后从1开始遍历,若 S [ 1 i ] S[1-i] 是循环字符串则输出 i i N / l e n N / len

题解:

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

int N, kase=0;
char s[maxn];
int Next[maxn];

void getnext()
{
    Next[0] = -1;
    int i = 0, j = -1;
    while(i<N)
    {
        while(j!=-1 && s[i]!=s[j]) j = Next[j];
        Next[++i] = ++j;
    }
    printf("Test case #%d\n", ++kase);
    for(int i=2;i<=N;i++)
    {
        if(Next[i]==0) continue;
        int len = i - Next[i];
        if(Next[i]%len==0) cout << i << ' ' << Next[i]/len+1 << endl;
    }
    putchar('\n');
}

int main()
{
    scanf("%d", &N); getchar();
    while(N)
    {
        gets(s);
        getnext();
        scanf("%d", &N); getchar();
    }
    return 0;
}

HUST-1010

对于字符串A, 将其重复多次,形成新的字符串AAA…AAAA,在其中截取一段,作为B.
现给定B字符串,求符合条件的最短的A

扫描二维码关注公众号,回复: 9220986 查看本文章
bcabcab
efgabcdefgabcde
3
7

思路:本题实际上就是在求B中的循环节长度,只不过前/后可以多/少一些部分,原来的方法依然是可求的。
代码略

发布了35 篇原创文章 · 获赞 15 · 访问量 1096

猜你喜欢

转载自blog.csdn.net/irimsky/article/details/102923705