kmp

数据结构实验之串一:KMP简单应用

半城伤御伤魂 提交于 2019-11-30 07:09:56
Problem Description 给定两个字符串string1和string2,判断string2是否为string1的子串。 Input 输入包含多组数据,每组测试数据包含两行,第一行代表string1(长度小于1000000),第二行代表string2(长度小于1000000),string1和string2中保证不出现空格。 Output 对于每组输入数据,若string2是string1的子串,则输出string2在string1中的位置,若不是,输出-1。 Sample Input abc a 123456 45 abc ddd Sample Output 1 4 -1 Hint Source #include <stdio.h> #include <stdlib.h> #include <string.h> int next[1000001]; void GetNextarr(char *p) // 计算next数组 { int len = strlen(p); next[0] = -1; // 初始化next[0]为-1 int k = -1; int j = 0; while(j < len - 1) { // p[k]表示前缀,p[j]表示后缀 if (k == -1 || p[j] == p[k]) { k++; j++; next[j] = k; //

KMP & AC自动机

痞子三分冷 提交于 2019-11-30 05:48:58
KMP 和 AC自动机 都可以解决字符串匹配问题 KMP是一对一匹配 AC自动机是多对一匹配 KMP KMP核心思想是 利用字符串的前缀与后缀相同,失配时跳到等于后缀的前缀,可以不必从头开始 。 这张图列举了字符"ABCDABD"所有的前缀和后缀 红色的表示前缀和后缀相等 例如: 用字符 P=“ABCDABCDE” 去匹配 字符 S = “ABCDABCDABCDABCD” 当匹配到 ABCDABCD ABCDABCD时 发现’A’与’E’不匹配 那指针就可以不必从头开始,可以跳到 ABCD ABCDE 从A开始匹配 原理很简单,就是因为后缀等于前缀,那么本来后缀能匹配的上的前缀依然能匹配上 现在开始构造后缀等于前缀的指针数组 (next) 这里用到了DP的思想 当计算第i个字符的next指针 去找第i-1个字符的next指针所指向的字符 要是这个字符的下一个字符等于第i个字符 那么第i个字符的next指针指向这个字符的下标 否则继续去寻找这个字符反而next指针所指向的字符(开始循环) 原理还是很简单 因为要找第i个字符next指针,第i-1个字符已经找到到它的next 所以就在第i-1个字符所构成的后缀 与之相等的前缀的后面一个去找第i个字符 code /* https://www.luogu.org/problem/P3375 P3375 【模板】KMP字符串匹配 */ #

Codeforces Round #558 (Div. 2) D kmp + dp

怎甘沉沦 提交于 2019-11-30 03:23:05
题目链接 题意:给你一个c串,你可以用任意小写字母替换c串中的 * 字符得到一个c',给你一个s和t串,定义:f(s1,s2) 为字符串 s2 在 s1 中出现的次数 ,求最大的 ans=f(c',s) - f(c',t)。 思路:首先预处理出 s 和 t 的next数组,然后,设dp【i】【j】【k】分别代表c串匹配到第 i 个字符,s串匹配到第 j 个字符,t串匹配到第 k 个字符的最大的答案,只能由前一个状态推出后面一个状态,如果当前状态没有值,那么就不能去推后一个状态,就continue,如果c【i】!= ’*‘ ,那么就直接kmp匹配,如果匹配到 s 串的最后一个字符,那么flag++,否则转移到下一个可以到达的状态,同理 t 串,t 串就flag - -。但是如果c【i】== ‘*’;就从 ‘ a ' 枚举到 ‘z ',然后kmp匹配再转移。 **:这题一定是拿已知当前状态去推导之后的状态。 #include<bits/stdc++.h> using namespace std; const int maxn=1005,inf=1e9; int d[maxn][55][55],next1[55],next2[55]; char c[maxn],s[55],t[55]; int n,m1,m2; void init() { int len; len=strlen(s);

kmp入门 洛谷模板题

≡放荡痞女 提交于 2019-11-30 01:06:04
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+100; char a[maxn],b[maxn]; int nexts[maxn]; int main() { scanf("%s%s",b,a); int len1=strlen(a); nexts[0]=-1; for(int i=0,j=-1;i<=len1;) { if(j==-1||a[i]==a[j])nexts[++i]=++j; else j=nexts[j]; } int len=strlen(b); int k=0; for(int i=0;i<len;i++) { while(k&&b[i]!=a[k])k=nexts[k]; k+=a[k]==b[i]?1:0; if(k==len1)printf("%d\n",i-len1+2); } for(int i=1;i<=len1;i++)cout<<nexts[i]<<' '; return 0; } 来源: CSDN 作者: 嘻嘻嘻西 链接: https://blog.csdn.net/weixin_44499508/article/details/103246364

KMP模板

╄→尐↘猪︶ㄣ 提交于 2019-11-29 14:23:58
const int N=1e6+10; //文本串的长度 const int M=1e4+10; //模式串的长度 char a[N]; //文本串 char b[M]; //模式串 int next0[M]; void find_next() { int len=strlen(b); int k=-1; next0[0]=-1; int j=0; while(j<len) { if(k==-1||b[j]==b[k]) { j++; k++; next0[j]=k; } else { k=next0[k]; } } } int kmp() { int i=0; int j=0; int alen=strlen(a); int blen=strlen(b); while(i<alen&&j<blen) { if(j==-1||a[i]==b[j]) { i++; j++; } else j=next0[j]; } if(j==blen) return i-j+1; //返回查找到所在的位置 return -1; //查找失败 } 来源: https://blog.csdn.net/qq_40727168/article/details/100830145

kmp hdu 2087

≡放荡痞女 提交于 2019-11-29 14:16:54
剪花布条 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 37980 Accepted Submission(s): 23204 http://acm.hdu.edu.cn/showproblem.php?pid=2087 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢? Input 输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。 Output 输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。 Sample Input abcde a3 aaaaaa aa # Sample Output 0 3 #include<cstdio> #include<cstring> const int maxt=1000+3; int i,j,k; int next[maxt]; char w

KMP(应用)

南笙酒味 提交于 2019-11-29 14:07:42
KMP(应用) 【求解字符串的周期(连续重复串)】: POJ 2406 Power Strings KMP自配后,观察 F a i l [ s t r l e n ( S ) ] Fail[strlen(S)] F a i l [ s t r l e n ( S ) ] ,手动模拟,可以发现,如果存在最小单元,那么一定是 S [ 0 到 s t r l e n ( s ) − F a i l [ s t r l e n ( S ) ] ] S[0到strlen(s)-Fail[strlen(S)]] S [ 0 到 s t r l e n ( s ) − F a i l [ s t r l e n ( S ) ] ] 。如果该单元长度是总长度的因数则是合法最小单元,否则该字符串的周期为1. int Fail [ N ] , len ; char s [ N ] ; void pre ( ) { int j = - 1 ; Fail [ 0 ] = - 1 ; for ( int i = 1 ; i < len ; ++ i ) { if ( j >= 0 && s [ j + 1 ] != s [ i ] ) j = Fail [ j ] ; if ( s [ j + 1 ] == s [ i ] ) j ++ ; Fail [ i ] = j ; } } int main ( )

kmp算法笔记(简单易懂)

好久不见. 提交于 2019-11-29 12:40:30
一般字符串比较长串m短串为n,那么用暴力方法复杂度为O(m*n) 但是kmp却可以达到O(m+n)!!!!!! 对于这个神奇的算法,我也是似懂非懂, 下面介绍一个简单的方法求kmp 1、求next数组   这个数组时kmp的灵魂!next数组时对于短串n求的   步骤:     1)next[0]=-1     2) next[i]=前面的字符串中最大公共子串长度     例子:     设m串为:a b a b c, 串长为5,那么next数组长度为5,下面是对应的next数组          可以看到,b下面有一个1,这个1是怎么得来的呢?》》是根据前面aba这个串得来的,aba串的最大公共子串长度为1     aba最大公共子串是a,因为从左边数连续的最大子串(小于母串长度)是a,从右边数连续最大子串也是a,所以next【3】=1                         c下面的2是由于前面的串abab的最大公共子串长度为2(公共子串为ab)                          再比如aaaa最大公共子串长度为3(从左边连续最大子串=从右边连续最大子串=aaa)                      2、使用next数组,和长串n短串m进行匹配   1、首先前三个都匹配上了,但是到箭头处不匹配了,下面进行m串移动      2、移动后如下图   

[算法讲解] KMP & EXKMP

允我心安 提交于 2019-11-29 11:30:16
KMP KMP作为一个广为人知的字符串匹配算法——也是本文的前一半。 旨在讲解next数组的求法,并使读者理解。 先扔代码 luoguP3375 【模板】KMP字符串匹配 #include<iostream> #include<cstring> using namespace std; const int N=5000002; int next[N]; string s1,s2; void init(string s){ for(int i=0,j=next[0]=-1,len=s.size();i<len;){ if(j==-1||s[i]==s[j]) next[++i]=++j; else j=next[j]; } } int main(){ cin >> s1 >> s2; init(s2); for(int i=0,j=0,len=s1.size();i<len;){ if(j==-1||s1[i]==s2[j]) ++i,++j; else j=next[j]; if(j==s2.size())cout << i-s2.size()+1 << endl; }for(int i=1,len=s2.size();i<=len;++i) cout << next[i] << " "; return 0; } 我们先看到 init 初始化函数。 void init(string

KMP算法

喜夏-厌秋 提交于 2019-11-29 10:29:42
长文章:https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html 板题:求子串在主串中出现的次数 #include<bits/stdc++.h> using namespace std; const int M=1e6+6; char S[M],T[M]; int nextt[M]; int ans=0; void makeNext(){ int m=strlen(T); nextt[0]=0; for (int i=1,j=0;i<m;i++){ while(j>0&&T[i]!=T[j]) j=nextt[j-1]; if(T[i]==T[j]) j++; nextt[i]=j; } } void kmp(){ int n,m; n = strlen(S); m = strlen(T); makeNext(); for (int i=0,q=0;i<n;i++){ while(q>0&&T[q]!=S[i]) q=nextt[q-1]; if(T[q]==S[i]) q++; if(q==m) ans++; } } int main() { while(~scanf("%s%s",S,T)) { ans=0; kmp(); printf("%d\n",ans); } return 0; } View Code 来源: