Kmp算法浅谈

Kmp算法浅谈

一.Kmp算法思想

在主串和模式串进行匹配时,利用next数组不改变主串的匹配指针而是改变模式串的匹配指针,减少大量的重复匹配时间。在Kmp算法中,next数组的构建是整个Kmp算法的核心所在。

二.Kmp核心之next数组的构建

(1)前缀,后缀的定义

(2)最长公共前后缀定义

(3)next数组的含义

next数组代表各个长度子串(这些字串的起始位置都为0)的最长公共前后缀长度,为了方便代码的编写next[0]定为-1,表示前0个字符根本不存在前后缀这一说法。其他的例如next[1]表示前一个字符的 最长公共前后缀 ,很明显根据前后缀的定义,next[1]=0;next[1]和next[0]在本博客说明的next数组构成中是唯一和确定的。

(4)最长公共前后缀定义及与next的联系

(5)对于一个模式串next数组到底能表示什么

首先根据上面的说法next数组表示了模式串长度为i的前缀的最长公共前后缀的的长度,所以说next可以来表示长度。这个时候我们在深究一下它表示的是谁的长度?它表示的是最长公共前后缀的!!!!,也就是说它可以表示模式串中第next[i]个元素的下标!!!,不懂的话看图就明白了

(6)如何利用next数组的性质避免重复匹配呢

三.如何用代码的形式得到next数组

首先上个代码

void Getnext(int next[],char *MyString)
{
   int j=0,k=-1;
   next[0]=-1;//规定,方便后面k的计算
   while(j<strlen(MyString)-1)//j不能超过整个串的长度
   {
      //j为当前字符,k为j前面那些字符的最长公共前后缀的下一个字符
      if(k == -1 || MyString[j] == MyString[k])next[++j] = ++k;
      //模式串的第一个字符就要比较的字符不一样,那我就要将模式串的下一个字符和我要比较的字符比较,且现在k还是为-1的,所以++j,++k
      else k = next[k];
   }
}
 

三.Kmp算法代码

得到了next后一切就简单了,无非就是设定两个“指针”分别指向主串和模式串,当出现不匹配时模式串的指针根据next数组移动就好了,直接上代码

int Kmp(char *T,int numt,char *P,int nump,int *next)//T为主串,P为模式串
{
    int i=0,j=0;//i为主串的指针,j为模式串的指针
    while(i<=numt-nump)
    {
        while((T[i]==P[j]&&i<numt)||j==-1) ++i,++j;//j==-1
//模式串第一个就和主串中要匹配的字符不匹配,主串字符后移一位,模式串的指针也从-1恢复到零
        if(j==nump)//找到匹配串
        return i-nump;//返回在主串中的起始位置
        j=next[j];
    }
    return -1;//表示无法找到
}
 

四.整个程序完整代码

#include <stdio.h>
#include <string.h>
void Getnext(int next[],char *MyString);
int Kmp(char *T,int numt,char *P,int nump,int *next);
const int SIZE=256;
int main()
{
    char *T=new char[SIZE];
    char *P=new char [SIZE];
    int *next=new int [SIZE];
    scanf("%s",T);
    scanf("%s",P);
    Getnext(next,P);
    for(int i=0;i<strlen(P);i++) printf("%d,",next[i]);
    printf("\n%d",Kmp(T,strlen(T),P,strlen(P),next));
    return 0;
}
void Getnext(int next[],char *MyString)
{
   int j=0,k=-1;
   next[0]=-1;
   while(j<strlen(MyString)-1)
   {
      if(k == -1 || MyString[j] == MyString[k])next[++j] = ++k;
      else k = next[k];
   }
}
int Kmp(char *T,int numt,char *P,int nump,int *next)//T为主串,P为模式串
{
    int i=0,j=0;//i为主串的指针,j为模式串的指针
    while(i<=numt-nump)
    {
        while((T[i]==P[j]&&i<numt)||j==-1) ++i,++j;
        if(j==nump)//找到匹配串
        return i-nump;//返回在主串中的起始位置
        j=next[j];
    }
    return -1;//表示无法找到
}
 

原文地址:https://www.cnblogs.com/PokimonMaster/p/12188845.html

时间: 2024-10-07 19:32:22

Kmp算法浅谈的相关文章

Pollard Rho算法浅谈

Pollard Rho介绍 Pollard Rho算法是Pollard[1]在1975年[2]发明的一种将大整数因数分解的算法 其中Pollard来源于发明者Pollard的姓,Rho则来自内部伪随机算法固有的循环 Pollard Rho算法在其他因数分解算法[3]中不算太出众,但其空间复杂度Θ(1)的优势和好打的代码使得OIer更倾向于使用Pollard Rho算法 毕竟试除法太慢了,谁没事打Pollard Rho不打试除法 Pollard Rho原理 生日悖论 如果一年只有365天(不计算闰

模拟退火算法浅谈

模拟退火算法(Simulate Anneal,SA)是一种通用概率演算法,用来在一个大的搜寻空间内找寻命题的最优解.模拟退火是由S.Kirkpatrick, C.D.Gelatt和M.P.Vecchi在1983年所发明的.V.?erný在1985年也独立发明此演算法.模拟退火算法是解决TSP问题的有效方法之一. 模拟退火的出发点是基于物理中固体物质的退火过程与一般组合优化问题之间的相似性.模拟退火算法是一种通用的优化算法,其物理退火过程由加温过程.等温过程.冷却过程这三部分组成. ——百度百科

算法浅谈——人人皆知却很多人写不对的二分法

本文始发于个人公众号:TechFlow   1  二分法可以说是鼎鼎大名,哪怕是没有学过编程的同学,也许说不上来二分法这个名字,但是对于其中的精髓应该都是有所了解的.不了解的同学也没关系,我一句话就能交代清楚:我们每次将一个集合一分为二,每次舍弃其中一半.早在两千多年前,庄子就搞清楚了二分法的精髓,他说:一尺之棰,日取其半,万世不竭.从这个角度来说,二分法可能是这个世界上最古老的算法之一了.二分法不仅古老,而且在计算机系统当中非常常见,许多系统当中都用到了二分法的思想.除此之外,在面试的时候,二

算法浅谈——递归算法与海盗分金问题

本文始发于个人公众号:TechFlow 最近看到一道很有意思的问题,分享给大家. 还是老规矩,在我们聊算法问题之前,先来看一个故事. 传说中,有5个海盗组成了一支无敌的海盗舰队,他们在最后一次的寻宝当中找寻到了100枚价值连城的金币.于是,很自然的,这群海盗面临分赃的问题.为了防止海盗内讧,残忍的海盗们制定了一个奇怪的规则: 他们决定按照功劳大小对五个人进行编号,由编号小的海盗先提出分配方案.如果方案能够得到大多数人的同意,那么就按照他提出的方案进行分配.如果不能通过,说明他已经失去了威望,海盗

算法浅谈——分治算法与归并、快速排序(附代码和动图演示)

在之前的文章当中,我们通过海盗分金币问题详细讲解了递归方法. 我们可以认为在递归的过程当中,我们通过函数自己调用自己,将大问题转化成了小问题,因此简化了编码以及建模.今天这篇文章呢,就正式和大家聊一聊将大问题简化成小问题的分治算法的经典使用场景--排序. 排序算法 排序算法有很多,很多博文都有总结,号称有十大经典的排序算法.我们信手拈来就可以说上来很多,比如插入排序.选择排序.桶排序.希尔排序.快速排序.归并排序等等.老实讲这么多排序算法,但我们实际工作中并不会用到那么多,凡是高级语言都有自带的

浅谈算法和数据结构系列汇总(转)

突然看到一个大神的系列文章讲的就是算法和数据结构,现在把它的文章集中分享给大家,向大神致敬: 浅谈算法和数据结构: 一 栈和队列 浅谈算法和数据结构: 二 基本排序算法 浅谈算法和数据结构: 三 合并排序 浅谈算法和数据结构: 四 快速排序 浅谈算法和数据结构: 五 优先级队列与堆排序 浅谈算法和数据结构: 六 符号表及其基本实现 浅谈算法和数据结构: 七 二叉查找树 浅谈算法和数据结构: 八 平衡查找树之2-3树 浅谈算法和数据结构: 九 平衡查找树之红黑树 浅谈算法和数据结构: 十 平衡查找

浅谈大型web系统架构

动态应用,是相对于网站静态内容而言,是指以c/c++.php.Java.perl..net等服务器端语言开发的网络应用软件,比如论坛.网络相册.交友.BLOG等常见应用.动态应用系统通常与数据库系统.缓存系统.分布式存储系统等密不可分. 大型动态应用系统平台主要是针对于大流量.高并发网站建立的底层系统架构.大型网站的运行需要一个可靠.安全.可扩展.易维护的应用系统平台做为支撑,以保证网站应用的平稳运行. 大型动态应用系统又可分为几个子系统: 1)Web前端系统 2)负载均衡系统 3)数据库集群系

浅谈Manacher算法与扩展KMP之间的联系

首先,在谈到Manacher算法之前,我们先来看一个小问题:给定一个字符串S,求该字符串的最长回文子串的长度.对于该问题的求解,网上解法颇多,时间复杂度也不尽相同,这里列述几种常见的解法. 解法一 通过枚举S的子串,然后判断该子串是否为回文,由于S的子串个数大约为,加上每次判断需要的时间,所以总的时间复杂度为,空间复杂度为. bool check(string &S, int left, int right) { while (left < right && S[left]

浅谈KMP算法及其next[]数组

KMP算法是众多优秀的模式串匹配算法中较早诞生的一个,也是相对最为人所知的一个. 算法实现简单,运行效率高,时间复杂度为O(n+m)(n和m分别为目标串和模式串的长度),比蛮力算法的O(nm)快了许多. 理解KMP算法,关键是理解其中的精髓——next[]数组. (统一起见,下文将目标字符串记作obj,将模式字符串记作pattern,这与后面的程序代码是一致的) 我们给一个字符串S定义一个next值,记作next(S),next(S)=n表示: (1)S的前n个字符构成的前缀,和后n个字符的后缀