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 ...
随机推荐
- Amazon Alexa 语音识别1 : 简介
Alexa是Amazon自家的语音识别技术,需要配合自家的Echo音箱使用.开发者可以在Amazon上建立自己的程序(Skill)来连接到自己的应用或是硬件.例如,用户家里有一套xx牌的智能灯,现在希 ...
- poj 3250 Bad Hair Day (单调栈)
http://poj.org/problem?id=3250 Bad Hair Day Time Limit: 2000MS Memory Limit: 65536K Total Submissi ...
- java单例模式使用及注意事项
1. 说明 1)单例模式:确保一个类只有一个实例,自行实例化并向系统提供这个实例 2)单例模式分类:饿单例模式(类加载时实例化一个对象给自己的引用),懒单例模式(调用取得实例的方法如getInstan ...
- 学习lamda表达式
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.L ...
- HDU 1754 I Hate It(线段树)
点我看题目 题意 :又是一道中问题,我就不说题意了.... 思路 : 线段树,这道题跟1166差不多,改一些地方就差不多了. #include <iostream> #include & ...
- Linux使用wake_up_interruptible()唤醒注册到等待队列上的进程
http://blog.sina.com.cn/s/blog_4770ef020101h48l.html 功能:唤醒注册到等待队列上的进程 原型: #include void ...
- background image position问题
在CSS中,背景图片的定位方法有3种: 1)关键字:background-position: top left; 2)像素:background-position: 0px 0px; 3)百分比:ba ...
- Java:JXL解析Excel文件
项目中,有需求要使用JXL解析Excel文件. 解析Excel文件 我们先要将文件转化为数据流inputStream. 当inputStream很大的时候 会造成Java虚拟器内存不够 抛出内存溢出 ...
- C# 系统应用之通过注册表获取USB使用记录(一)
该文章是“个人电脑历史记录清除软件”项目的系统应用系列文章.前面已经讲述了如何清除IE浏览器的历史记录.获取Windows最近访问文件记录.清除回收站等功能.现在我需要完成的是删除USB设备上的U盘. ...
- MS dos版本
1981年,MS-DOS 1.0发行,作为IBM PC的操作系统进行捆绑发售,支持16k内存及160k的5寸软盘.在硬件昂贵,操作系统基本属于送硬件奉送的年代,谁也没能想到,微软公司竟会从这个不起眼的 ...