UVALive 3026 Period (KMP算法简介)

kmp的代码很短,但是不太容易理解,还是先说明一下这个算法过程吧。

朴素的字符串匹配大家都懂,但是效率不高,原因在哪里?

匹配过程没有充分利用已经匹配好的模版的信息,比如说,

i是文本串当前字符的下标,j是要匹配的模版串当前正在匹配的字符的下标。(下标都从零开始)

当匹配到i = 4, j = 4的时候失配了,朴素的匹配做法是往右边移一位然后从j开始扫,这样做效率很低。

不难发现前面已经匹配好的串ab是相同的最大前缀后缀。把串移动到后缀的第一个位置正好是

朴素的匹配过程中第一次匹配能把这个前缀匹配匹配完的位置!因此令j = f[j-1] = 2。

模版串下面这个f数组又是怎么来的呢?

寻找最大前缀后缀过程本质上也是一个匹配。

i表示当前要求f[i]的下标,j表示之前串已经匹配的最大前缀后缀长度。(j = -1表示0号位置也没有匹配上)

当i = 6时,之前已经匹配了j个,所以只要i只要从j下标位置开始比较就行了。当匹配的时候f[i] = j+1。

如果不匹配,利用前面已经得到的f值进行匹配。

当i = 7, j = 3时,发生失配,利用之前的f值,可以知道a是最长的前缀和后缀,那么只需要从a开始匹配,因此令j = f[j-1],

重复上述过程直到匹配或j = -1的时候为止。当前就等于: f[i] = j+1。(j=-1表示没有匹配也是为了方便统一处理)

在代码中,因为当j = 0的时候,j = f[j-1]不要表示,因此把整个f数组向右边移动一位。此时只需把上述过程的j = f[j-1]替换成j = f[j]。

----------------------------------------------分割线----------------------------------------------------------------

这道题要求前缀的最小循环周期。

先构造一个循环的串,然后进行求失配函数f的过程,当第一次前缀长度等于后缀长度并且各占一半的时候,这个前缀一定是最小的循环节。(从第一个结论开始用归纳法证明)

可以归纳出一个结论:在每个循环节终止的位置 i-f[i] ==最短循环节长度。

反过来i能被(i-f[i])整除可以推出i-f[i]是最短循环节。(同样用归纳法)

kmp之前不太理解,只会套。为学习ac自动机,kmp还是基础。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
int f[maxn];
char str[maxn];

void getF(char *s)
{
    f[0] = -1;
    for(int i = 0, j = -1; s[i]; ){
        while(~j && s[i] != s[j]) j = f[j];
        f[++i] = ++j;
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    int n,kas = 0;
    while(scanf("%d\n",&n),n){
        gets(str);
        getF(str);
        printf("Test case #%d\n",++kas);
        for(int i = 2; i <= n; i++){
            if(f[i] && i%(i-f[i]) == 0)
                printf("%d %d\n",i,i/(i-f[i]));
        }
        putchar(‘\n‘);
    }
    return 0;
}
时间: 2024-11-09 19:58:59

UVALive 3026 Period (KMP算法简介)的相关文章

Uvalive - 3026 Period (kmp求字符串的最小循环节+最大重复次数)

参考:http://www.cnblogs.com/jackge/archive/2013/01/05/2846006.html 总结一下,如果对于next数组中的 i, 符合 i % ( i - next[i] ) == 0 && next[i] != 0 , 则说明字符串循环,而且 循环节长度为:   i - next[i] 循环次数为:       i / ( i - next[i] ) 1 #include <iostream> 2 #include <cstdi

UVALive - 3026 - Period (KMP)

UVALive - 3026 Period Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want

【暑假】[实用数据结构]UVAlive 3026 Period

UVAlive 3026 Period 题目: Period Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive),

UVALIVE 3026 Period

题意:给你一个字符串,问第i位前是否有循环节,若存在,则循环节是多少? 思路:考察失配函数f[i]的意义.只要i%(i-f[i])==0,则循环节长度为i/(i-f[i]).字符在[0,f[i]],[i-f[i],i]范围内的相等,所以如果存在循环节则每i-f[i]可以分为一段.理解起来比较抽象,模拟一遍. 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib

【数据结构&amp;&amp;算法系列】KMP算法介绍及实现(c++ &amp;&amp; java)

KMP算法如果理解原理的话,其实很简单. KMP算法简介 这里根据自己的理解简单介绍下. KMP算法的名称由三位发明者(Knuth.Morris.Pratt)的首字母组成,又称字符串查找算法. 个人觉得可以理解为最小回溯算法,即匹配失效的时候,尽量少回溯,从而缩短时间复杂度. KMP算法有两个关键的地方,1)求解next数组,2)利用next数组进行最小回溯. 1)求解next数组 next数组的取值只与模式串有关,next数组用于失配时回溯使用. 在简单版本的KMP算法中,每个位置 j 的 n

【原创】通俗易懂的讲解KMP算法及代码实现

一.本文简介 本文的目的是简单明了的讲解KMP算法的思想及实现过程. 网上的文章的确有些杂乱,有的过浅,有的太深,希望本文对初学者是非常友好的. 其实KMP算法有一些改良版,这些是在理解KMP核心思想后的优化. 所以本文重点是讲解KMP算法的核心,文章最后会有涉及一些改良过程. 二.KMP算法简介 KMP算法是字符串匹配算法的一种.它以三个发明者命名,Knuth-Morris-Pratt,起头的那个K就是著名科学家Donald Knuth. 三.KMP算法行走过程 首先我们先定义两个字符串作为示

字符串模式匹配算法之二:KMP算法

KMP算法简介 KMP算法全称叫做Knuth-Morris-Pratt Algorithm. 被搜索的字符串称为主串,待搜索的字符串称为模式串. 我们知道朴素模式匹配算法:http://blog.csdn.net/chfe007/article/details/43448655是很低效的,KMP算法从模式串出发,发现模式串中隐藏的信息来减少比较的次数,具体如何做到的可以移步这个链接:http://kb.cnblogs.com/page/176818/ KMP算法的关键在于next数组值的推导.

从暴力匹配到KMP算法

前言 现在有两个字符串:\(s1\)和\(s2\),现在要你输出\(s2\)在\(s1\)当中每一次出现的位置,你会怎么做? 暴力匹配算法 基本思路 用两个指针分别指向当前匹配到的位置,并对当前状态进行分类讨论:若相同则继续往下匹配,否则回溯 大致思路 用\(i\)来存储\(s1\)当前匹配到的位置,用\(j\)来存储\(s2\)当前匹配到的位置,则可得初始状态下\(i=j=0\). 对于当前状态,有两种可能性: ①:\(s1[i]==s2[j]\).则\(i++,j++\) ②:\(s1[i]

UVAlive 3026 KMP 最小循环节

KMP算法: 一:next数组:next[i]就是前面长度为i的字符串前缀和后缀相等的最大长度,也即索引为i的字符失配时的前缀函数. 二:KMP模板 1 /* 2 pku3461(Oulipo), hdu1711(Number Sequence) 3 这个模板 字符串是从0开始的 4 Next数组是从1开始的 5 */ 6 #include <iostream> 7 #include <cstring> 8 using namespace std; 9 10 const int m