经典问题 : 给出一个由某个循环节构成的字符串,要你找出最小的循环节,例如 abababab 最小循环节当是 ab ,而类似 abab 也可以成为它的循环节,但并非最短。

分析 :

对于上述问题有两个结论

如果对于next数组中的 i, 符合 i % ( i - next[i] ) == 0 && next[i] != 0 , 则说明字符串循环,而且

循环节长度为:    i - next[i]

循环次数为:       i / ( i - next[i] )

水平有限,用自己的语言描述怕有差错,给出一个参考博客  ==>  http://www.cnblogs.com/jackge/archive/2013/01/05/2846006.html

再抛一个问题 : 有没有想过对于一个不完整的循环串要补充多少个才能使得其完整?

答案是==>(循环节长度) - len%(循环节长度) 即 (len - next[len]) - len%(len - next[len])

为什么? (以下胡扯,看不懂就掠过吧.........)

首先考虑整串就是循环节构成的情况,类似 abcxabcx 观察构造出来的next值显然满足上式,得出答案 0

那现在考虑不完整的情况,例如 abcabca 、其 next 值为 -1 0 0 0 1 2 3 4 。现在考虑末尾的 a,若没有它,而是将 c 作为末尾则会在 len 失配的时候会回溯道下一个循环节的末尾即 abca , 那现在多了一个a,那么回溯当然也应该是(循环节长度 + 1) 即 abcab,故 len 那里无论是否刚好为循环节的末尾,只是个"残"的末尾,未圆满的循环节,len-next[len]也是循环节长度,那需要补多少个呢?现在就很显然了!下面相关题目的 ① 就是这样的一个问题。

相关题目 :

HDU 3746 Cyclic Nacklace

题意 : 给出一个字符串,问你最少补充多少个字母才能使得字符串由两个或者以上的循环节构成

分析 : 由结论可知,如果字符串循环,那么最小循环节的长度为 len - next[len] ,并且这个字符串总长能被循环节长度整除说明字符串已经循环,否则 len % (len - next[len]) 则为多出来的部分,例如 abcabcab ==> len - next[len] = 3,而 len % 3 == 2 很明显就是余出来两个,这两个应当是循环节的头两个字母,对于其他串也可以自己模拟看看,所以需要补充的就是 循环节长度 - 多余出来的长度

#include<stdio.h>
#include<string.h>
using namespace std;
;
char mo[maxn];
int Next[maxn], moL, nCase;
inline void GetNext()
{
    , j = -;
    Next[i] = j;
    while(i < moL){
         && mo[i]!=mo[j]) j = Next[j];
        Next[++i] = ++j;
    }
}
int ans()
{
    GetNext();
    ) return moL;

    int Period_len = moL - Next[moL];
    int Remain = moL % Period_len;

    ) ;
    return Period_len - Remain;
}
int main(void)
{
    scanf("%d", &nCase);
    while(nCase--){
        scanf("%s", mo);
        moL = strlen(mo);
        printf("%d\n", ans());
    }
    ;
}

POJ 1961 Period

题意 : 给出一个字符串,叫你给出这个字符串存在的不同循环节长度以及个数 ( 循环节构成的不一定是整个字符串,也有可能是其子串 )

分析 : 根据以上的结论,我们只要让构造出字符串的next数组,而后一个for循环判断当前长度和当前最小循环节长度是否是倍数关系,即 i % ( i - next[i] ) == 0 && next[i] != 0,就能判断是否为一个循环节了,循环节的长度自然是 i / (i-next[i])

#include<stdio.h>
using namespace std;
;
char mo[maxn];
int Next[maxn], moL;
inline void GetNext()
{
    , j = -;
    Next[i] = j;
    while(i < moL){
         && mo[j]!=mo[i] ) j = Next[j];
        Next[++i] = ++j;
    }
}
inline void PrintAns()
{
    GetNext();
    int Period;
    ; i<=moL; i++){
        ){
            Period = i - Next[i];
            ){
                printf("%d %d\n", i, i/Period);
            }
        }
    }puts("");
}
int main(void)
{
    ;
    while(~scanf("%d", &moL) && moL){
        scanf("%s", mo);
        printf("Test case #%d\n", Case++);
        PrintAns();
    }
    ;
}

HUST 1010  The Minimum Length

题意 : 假设 A 是一个循环字符串,现在截取 A 的某一段子串 B 出来,给出 B 问你构成 A 的循环节的最小长度是多少?

分析 : 既然是循环串当中截取出来的,那么只要根据结论公式算出最小循环节长度即是答案,可以证明证明这样做永远是最优的。以下代码由于HUST OJ崩了,所以不知道结果
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
;
int Next[maxn], moL;
char mo[maxn];
inline void GetNext()
{
    , j = -;
    Next[i] = j;
    while(i < moL){
         && mo[i]!=mo[j]) j = Next[j];
        Next[++i] = ++j;
    }
}
int Ans()
{
    GetNext();
    ) return moL;
    else return moL - Next[moL];
}
int main(void)
{
    while(~scanf("%s", mo)){
        moL = strlen(mo);
        printf("%d\n", Ans());
    }
    ;
}

POJ 2406 Power String

题意 : 给你一个字符串,问你它由多少个相同的字符串拼接而成

分析 : 直接找算出最小循环节长度,如果字符循环,则答案为 len / (循环节长度) ,而对于 len % (循环节长度) != 0 和 next[len] == 0 的情况答案就是 1 了

#include<string.h>
#include<stdio.h>
using namespace std;
;
int Next[maxn], moL;
char mo[maxn];
inline void GetNext()
{
    , j = -;
    Next[i] = j;
    while(i < moL){
         && mo[i]!=mo[j]) j = Next[j];
        Next[++i] = ++j;
    }
}
int Ans()
{
    GetNext();
    ) ;
    int Period = moL - Next[moL];
    ) ;
    return moL / Period;
}
int main(void)
{
    ]!='.'){
        moL = strlen(mo);
        printf("%d\n", Ans());
    }
    ;
}

POJ 2752 Seek the Name, Seek the Fame

题意 : 给出一个字符串,问你所有关于这个字符串的前缀和后缀相同的长度,比如 abcab 有 1 "a"、2 "ab"、5 "abcab"

分析 : 这里就要巧妙利用到 next 数组的性质了,根据next数组定义可以知道 next[len] 表示一个从头开始长度为 next[len] 的前缀和相同长度的后缀相等,那么next[ next[len] ]呢?next[ next[ next[len] ] ]呢?这里的一层层嵌套实际上都是一个长度为 next[ next[len] ] 或者 长度 next[ next[ next[len] ] ]的前缀和后缀相等,自己构造个数组画画图也能得出来这个规律,那么到此,这个问题是不是被圆满的解决了呢!

#include<string.h>
#include<stack>
#include<stdio.h>
using namespace std;
;
char mo[maxn];
int Next[maxn], moL;
inline void GetNext()
{
    , j = -;
    Next[i] = j;
    while(i < moL){
         && mo[j]!=mo[i]) j = Next[j];
        Next[++i] = ++j;
    }
}
inline void PrintAns()
{
    moL = strlen(mo);
    GetNext();
    int tmp = Next[moL];
    stack<int> ans;///根据题目要求需要递增输出长度,而我们得出的答案顺序正好相反,所以利用栈存储
    ){///直到头为止
        ans.push(tmp);
        tmp = Next[tmp];
    }
    while(!ans.empty()){
        int Top = ans.top(); ans.pop();
        if(Top) printf("%d ", Top);
    }
    printf("%d\n", moL);
}
int main(void)
{
    while(~scanf("%s", mo)){ PrintAns(); }
    ;
}

KMP解决字符串最小循环节相关问题的更多相关文章

  1. hdu 4333"Revolving Digits"(KMP求字符串最小循环节+拓展KMP)

    传送门 题意: 此题意很好理解,便不在此赘述: 题解: 解题思路:KMP求字符串最小循环节+拓展KMP ①首先,根据KMP求字符串最小循环节的算法求出字符串s的最小循环节的长度,记为 k: ②根据拓展 ...

  2. poj 2406 Power Strings【字符串+最小循环节的个数】

                                                                                                      Po ...

  3. [POJ2406&POJ1961]用KMP解决字符串的循环问题两例

    翻阅了一下网上资料,发现大部分都说这题是找规律...或是说YY出的一个算法..不会证明... 然后就脑补了一下证明 ~ 结论:对于一个字符串S[1..N],如果N mod (N-next[N])=0 ...

  4. KMP解决最小循环节问题

    # 10035. 「一本通 2.1 练习 1」Power Strings [题目描述] 给定若干个长度 $\le 10^6$​​ 的字符串,询问每个字符串最多是由多少个相同的子字符串重复连接而成的.如 ...

  5. [KMP求最小循环节][HDU3746][Cyclic Nacklace]

    题意 给你个字符串,问在字符串末尾还要添加几个字符,使得字符串循环2次以上. 解法 无论这个串是不是循环串 i-next[i] 都能求出它的最小循环节 代码: /* 思路:kmp+字符串的最小循环节问 ...

  6. KMP + 求最小循环节 --- POJ 2406 Power Strings

    Power Strings Problem's Link: http://poj.org/problem?id=2406 Mean: 给你一个字符串,让你求这个字符串最多能够被表示成最小循环节重复多少 ...

  7. HDU 3746 (KMP求最小循环节) Cyclic Nacklace

    题意: 给出一个字符串,要求在后面添加最少的字符是的新串是循环的,且至少有两个循环节.输出最少需要添加字符的个数. 分析: 假设所给字符串为p[0...l-1],其长度为l 有这样一个结论: 这个串的 ...

  8. [KMP求最小循环节][HDU1358][Period]

    题意 求所有循环次数大于1的前缀 的最大循环次数和前缀位置 解法 直接用KMP求最小循环节 当满足i%(i-next[i])&&next[i]!=0 前缀循环次数大于1 最小循环节是i ...

  9. HDU 1358 Period(KMP+最小循环节)题解

    思路: 这里只要注意一点,就是失配值和前后缀匹配值的区别,不懂的可以看看这里,这题因为对子串也要判定,所以用前后缀匹配值,其他的按照最小循环节做 代码: #include<iostream> ...

随机推荐

  1. PAT(B) 1052 卖个萌(Java:0分 待解决,C:20分)

    题目链接:1052 卖个萌 (20 point(s)) 题目描述 萌萌哒表情符号通常由"手"."眼"."口"三个主要部分组成.简单起见,我们 ...

  2. 在vue中使用ElementUI

    完整引用ElementUI: 安装:在需要使用到的vue项目目录下,使用npm下载安装: npm/cnpm i element-ui -S/--save <!-- 引入样式 --> < ...

  3. ALV报表——ALV颜色设置(三)

    目录 一.行 二.列 三.单元格 四.附ALV的颜色代码 一.行:用Layout相关属性设置 代码: *Report ZRFI001_XFL_TEST REPORT ZRFI001_XFL_TEST ...

  4. Qt更新组件出现(“要继续此操作,至少需要一个有效且已启用的储存库”)

    Qt更新组件出现(“要继续此操作,至少需要一个有效且已启用的储存库”)   目的: 当时在安装Qt时,有些组件暂时没用着,然后过一段时间后,需要用到某些该组件时,不用删掉重新再安装. 操作: Wind ...

  5. springboot_3

    1. 返回数据与返回页面 在写web项目的时候,controller里的返回值一般分为两种,一种是返回页面,也就是ModeAndView,另一种是直接返回数据,比如json格式的数据. 返回一个页面, ...

  6. snort_inline

    snort_inline Link   http://snort-inline.sourceforge.net/oldhome.html What is snort_inline? snort_inl ...

  7. iOS应用开发---返回到指定界面

    关于ios中 viewcontroller的跳转问题,其中有一种方式是采用navigationController pushViewController 的方法,比如我从主页面跳转到了一级页面,又从一 ...

  8. 如何:确定已安装的 .NET Framework 版本

    用户可在他们的计算机上安装和运行 .NET Framework 的多个版本. 当你开发或部署应用时,你可能需要知道用户的计算机上安装了哪些 .NET Framework 版本. .NET Framew ...

  9. 【Java】接口和抽象类总结

    一.接口 1.1 成员变量(其实是常量) 1.2 方法 二.抽象类 2.1 成员变量 2.2 方法 一.接口 1.1 成员变量(其实是常量) 成员变量默认用 public static final修饰 ...

  10. springboot系列(十)springboot整合shiro实现登录认证

    关于shiro的概念和知识本篇不做详细介绍,但是shiro的概念还是需要做做功课的要不无法理解它的运作原理就无法理解使用shiro: 本篇主要讲解如何使用shiro实现登录认证,下篇讲解使用shiro ...