KMP学习总结
初学,理解可能不是那么准确~~
Next数组的含义:next[i]表示第0个元素到第i个元素组成的字符串的最大前缀后缀。Next[0]=0显然。
所以KMP的原理就是
通过找出每一阶段最大的相等的前缀后缀,那么匹配到某个字符失配时就可以从前缀的下一个字母开始匹配,而不用再回退匹配。使复杂度降从O(m^n)到O(m+n)。
最重要的就是求next数组,而且next数组在很多题都有应用,不止KMP。
而得到next数组的原理如下:
(画风就是这么洒脱,没办法~~~)
色的如图,如果比较到p,如果p点元素和q点元素相等,那么直接S1的长度加1就是next[q]了,即next[q]=next[q-1]+1。
但是如果不等,就要在S1中找到一个短一点的字符串,如棕色的那段,那样,因为黄色的那段S2和S1是相等的,那么在S1中找到的最长前缀后缀也和S2的后缀相等,这时,如果A点那里和q相等,那么next[q]就是棕那段长度+1喽~如果不相等,再向前减,对,这个过程就是代码里那里【k=next[k];】。如果到紫色的那里B和q相同,那么next[q]为紫色的长度+1.如果一直不相等,只能是0喽~
代码如下(代码原网址链接):
void makeNext(const char P[],int next[])
{
int q,k;//q:模版字符串下标;k:最大前后缀长度
int m = strlen(P);//模版字符串长度
next[0] = 0;//模版字符串的第一个字符的最大前后缀长度为0
for (q = 1,k = 0; q < m; ++q)//for循环,从第二个字符开始,依次计算每一个字符对应的next值
{
while(k > 0 && P[q] != P[k])//递归的求出P[0]•••P[q]的最大的相同的前后缀长度k
k = next[k-1];
if (P[q] == P[k])//如果相等,那么最大相同前后缀长度加1
{
k++;
}
next[q] = k;
}
}
但很多时候next数组的意义是:next[i]表示第0个元素到第i-1个元素组成的字符串的前缀后缀,也就是如果把上面讨论的数组定义为nexta的话,那么nexta[i]=next[i+1] , 即nexta[0]=next[1]……nexta[n-1]=next[n],并定义next[0]=-1。
代码如下:
void GetNext()
{
//这个代码的原理和上差不多,就是改的短了些
int j = 0, k = -1;
Next[0] = -1;
while (j <= tlen)
{
if (k == -1 || T[j] == T[k])
{
Next[++j] = ++k;
}
else
k = Next[k];
}
} int KMP_Index()
{
int i = 0, j = 0;
GetNext();
while (i < slen && j < tlen)
{
if (j == -1 || S[i] == T[j])
{
i++;
j++;
}
else
j = Next[j];
}
if (j == tlen)
return i - tlen;
return -1;
}
也可以求一个字串出现的次数,代码稍作改动即可:
int KMP_Count()
{
int ans = 0;
int i = 0, j = 0;
GetNext();
while (i != slen && j != tlen)
{
if (S[i] == T[j] || j == -1)
++i, ++j; //第一次发现还可以这样写~
else
j = Next[j];
if (j == tlen)
{
++ans;
j = Next[j];
}
}
return ans;
}
举例说明理解一下
对于tytytyty
tytytyty // ↓子串 // ↓前缀后缀
next[0] = -1
next[1] = 0 // t
next[2] = 0 // ty
next[3] = 1 // tyt // t
next[4] = 2 // tyty // ty
next[5] = 3 // tytyt // tyt
next[6] = 4 // tytyty // tyty
next[7] = 5 // tytytyt // tytyt
next[8] = 6 // tytytyty // tytyty
KMP入门题
hdu2087 AC代码:
/*******************************************************
Problem : 2087 ( 剪花布条 ) Judge Status : Accepted
RunId : 14705531 Language : G++ Author : G_lory
Code Render Status : Rendered By HDOJ G++ Code Render Version 0.01 Beta
*******************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; const int N = 1005; char s[N]; // 原字符串
char t[N]; // 匹配子串
char nt[N]; // nt[i]表示t第0~i-1个元素组成的字符串的前缀后缀 int slen, tlen; // 字符串 s, t 的长度 void get_next()
{
int j = 0, k = -1;
nt[0] = -1;
while (j <= tlen)
{
if (k == -1 || t[j] == t[k])
{
nt[++j] = ++k;
}
else
k = nt[k];
}
} int kmp_cnt()
{
int ans = 0;
int i = 0, j = 0;
get_next();
while (i != slen && j != tlen)
{
if (s[i] == t[j] || j == -1)
++i, ++j;
else
j = nt[j];
if (j == tlen)
{
++ans;
//j = nt[j];
j = 0;
}
}
return ans;
} int main()
{
while (scanf("%s", s) != EOF) {
slen = strlen(s);
if (slen == 1 && s[0] == '#') break;
scanf("%s", t);
tlen = strlen(t);
printf("%d\n", kmp_cnt());
}
return 0;
}
hdu1711 AC代码:
/***********************************************************
Problem : 1711 ( Number Sequence ) Judge Status : Accepted
RunId : 14705762 Language : G++ Author : G_lory
Code Render Status : Rendered By HDOJ G++ Code Render Version 0.01 Beta
************************************************************/
#include <iostream>
#include <cstdio>
using namespace std; int ss[1000005];
int tt[10005];
int nt[10005];
int slen, tlen; void get_next()
{
int j = 0, k = -1;
nt[0] = -1;
while (j <= tlen)
{
if (k == -1 || tt[j] == tt[k])
{
nt[++j] = ++k;
}
else
k = nt[k];
}
} int kmp_idx()
{
int i = 0, j = 0;
get_next();
while (i < slen && j < tlen)
{
if (j == -1 || ss[i] == tt[j]) ++i, ++j;
else j = nt[j];
}
if (j == tlen)
return i - tlen;
return -1;
} int main()
{
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &slen, &tlen);
for (int i = 0; i < slen; ++i) scanf("%d", ss + i);
for (int i = 0; i < tlen; ++i) scanf("%d", tt + i);
int ans = kmp_idx();
printf("%d\n", ans == -1 ? -1 : ans + 1);
}
return 0;
}
KMP学习总结的更多相关文章
- KMP学习之旅
说起kmp就要从字符串的匹配说起,下面我们谈谈字符串的匹配 给定一个原字符串:bababababababababb,再给定一个模式串:bababb,求模式串是否在源字符串中出现 最简单的方法就是遍历源 ...
- KMP学习笔记
功能 字符串T,长度为n. 模板串P,长度为m.在字符串T中找到匹配点i,使得从i开始T[i]=P[0], T[i+1]=P[1], . . . , T[i+m-1]=P[m-1] KMP算法先用O( ...
- KMP学习
刚才看了(连接)写的翻译,把kmp算法的工作过程讲的很不错,kmp算法的核心是next,next为什么要那么赋值?其实就是前缀和后缀的最大匹配值,用这个值在匹配失败的时候可以跳过一个不必要的匹配. ...
- kmp学习小结
KMP 简要说明 \(kmp\)是一个非常神奇的东西.它的\(fail(next)\)数组\(f[i]\)就表示\(1\)~\(i\)这个串的最长公共前缀后缀长度.根据这个\(fail\)数组,在匹配 ...
- 扩展kmp学习笔记
kmp没写过,扩展kmp没学过可还行. 两个愿望,一次满足 (该博客仅用于防止自己忘记,不保证初学者能看懂我在瞎bb什么qwq) 用途 对于串\(s1,s2\),可以求出\(s2\)与\(s1\)的每 ...
- 126B Password[扩展kmp学习]
题目大意 给你一个字符串,求它的一个子串使得这个子串即使前缀又是后缀又出现在不是前缀且不是后缀的地方 分析 扩展kmp就是定义z[i]表示i~n的子串与整个串的最长公共前缀的长度是z[i] 所以这个题 ...
- 扩展kmp 学习笔记
学习了一下这个较为冷门的知识,由于从日报开始看起,还是比较绕的-- 首先定义 \(Z\) 函数表示后缀 \(i\) 与整个串的 \(lcp\) 长度 一个比较好的理解于实现方式是类似于 \(manac ...
- Kuangbin 带你飞 KMP扩展KMP Manacher
首先是几份模版 KMP void kmp_pre(char x[],int m,int fail[]) { int i,j; j = fail[] = -; i = ; while (i < m ...
- poj(2406) kmp
题目链接:https://vjudge.net/problem/POJ-2406 kmp学习:https://blog.csdn.net/starstar1992/article/details/54 ...
随机推荐
- Unity3d Shader开发(二)SubShader
(1)SubShader Unity中的每一个着色器都包含一个subshader的列表,当Unity需要显示一个网格时,它能发现使用的着色器,并提取第一个能运行在当前用户的显示卡上的子着色器. 当Un ...
- caffe之(四)全连接层
在caffe中,网络的结构由prototxt文件中给出,由一些列的Layer(层)组成,常用的层如:数据加载层.卷积操作层.pooling层.非线性变换层.内积运算层.归一化层.损失计算层等:本篇主要 ...
- Discuz CDN优化方案
DZ整体来说CDN是有点蛋疼的,因为毕竟琐碎,貌似大部分帖子都没有说全,这里罗列一下,给在用的孩儿们一点参考: 1.在后台设置CSS/JS走CDN路径,具体[全局]-[性能优化]-[服务器优化] 2. ...
- 将java类的泛型集合转换成json对象
一般用extjs开发传输都是用json比较多,这个将来大家也许会用到... ConvertJsonUtils.java package com.sunweb.util.jsonfactory; imp ...
- RubyCritic:一款不错的检测代码质量工具
关注代码质量是高效开发必须要做的一件事,那么在 Ruby 开发的过程中,是否有什么好的代码质量检测工具呢?下面由 Ruby 工程师路英瑞介绍一下 RubyCritic--一款还不错的代码质量检测工具. ...
- POJ 3159 Candies(差分约束)
http://poj.org/problem?id=3159 题意:有向图,第一行n是点数,m是边数,每一行有三个数,前两个是有向边的起点与终点,最后一个是权值,求从1到n的最短路径. 思路:这个题让 ...
- SQLite入门与分析(八)---存储模型(3)
写在前面:接上一节,本节主要讨论索引页面格式,以及索引与查询优化的关系. (1)索引页面格式sqlite> select * from sqlite_master;table|episodes| ...
- Android EditText多行显示及所有属性
android:id="@+id/editSms" android:layout_width="fill_parent" android:layout_heig ...
- CP_THREAD_ACP与CP_ACP
在使用MultiByteToWideChar的时候,大部分都知道上述两个参数,MSDN上的解释也是简单到极致.通常我们会选择使用CP_ACP,但是总有人会在没有真正明白它们之间的区别前使用CP_THR ...
- 多核CPU怎么理解
简而言之,双核处理器即是基于单个半导体的一个处理器上拥有两个一样功能的处理器核心.换句话说,将两个物理处理器核心整合入一个核中.企业IT管理者们也一直坚持寻求增进性能而不用提高实际硬件覆盖区的方法.多 ...