【gif图文】KMP算法(从暴力匹配到快速匹配)

简介: 【gif图文】KMP算法(从暴力匹配到快速匹配)

从暴力匹配到快速匹配(KMP算法)


学习kmp算法前,首先要先了解什么是kmp算法,kmp算法具体优点是什么,kmp的主要应用方向在哪。

然后才是,代码实现


带着以上问题,我们来一步一步学习kmp算法。

问题: 给一串字符,让你从中找出与模式串相同的一段子串

例如:给这么一段字符

(主串:ABBABBABABAAABABAAA)

(模式串:ABAABABAA)

要求从主串中找出与模式串相同的一段子串


那么,一般方法,就是暴力匹配


暴力匹配(BF算法)


直接给图

77bb2e09bd9c91595961d556f769d480_0e2f5958a03b17d807be5cadcab9a7c8.gif


很直观,也是多数人直接想到的方法,就是模式串中每一个字符和主串一一进行比较,如果出现不同的,模式串后移一位,重复上述操作,一直找到与模式串相同的一段子串,这种方法称为暴力匹配。

优点:方法简单,暴力。

缺点:平均时间复杂度O ( n * m )


思考:能否利用已部分匹配过的信息而加快模式串的滑动速度?

答案:KMP算法


快速匹配(KMP算法)


还是先给图

image.gif

从上图中,箭头指向失配元素,小方框内是最大前缀和最大后缀,大方框中是要已经匹配的字符串,我们就是从这串字符做文章的

(重点!!已匹配的字符串 下文就此展开)

然后将最大前缀移动到最大后缀的位置,就完成了一次最优”滑动“


那么什么是最大前缀和最大后缀呢?


最大前缀&最大后缀(如果了解,可跳过)


给图!

红色下划线:最大前缀

黑色下划线:最大后缀

8d62c7d78f67ee56cdd0e449bf1c7c2f_46039af3c573059624084421951b44e2.png


滑动大小取决于模式串


当模式串出现失配,以此处向前从已匹配的字符串中找最大前缀和最大后缀,因为前面字符和主串字符一致,而滑动是将最大前缀移动到最大后缀的位置上最大前缀和最大后缀是从子串中找,

既然如此,


当模式串第m个字符失配,那么就从模式串串1—m中找最大前缀和最大后缀,将最大前缀移动到最大后缀的位置上

以上(从那么开始)操作,和主串无关,既


给图

dfb0a2dd913751ed75ac607a656dcb88_096262fe59ebc9b88f3adf72374626bc.png


KMP算法代码实现


由以上的理解,你大概知道了kmp算法的基本原理。那么,如何实现呢?

给代码前,了解一下“next[]”数组


next[]数组(如已了解,可跳过)


当光标指向失配字符时,我们需要移动模式串,那么移动后,我们的光标应该指向什么位置?

17909cbfd21e7c5540ce03bd0d3dd3f5_52ec63060d72d5246e859d17bab00938.gif

答:光标指向最大前缀长度+1的位置上

可见,模式串每个位置,都能对应这么一个数:以此向前已匹配的字符串的最大前缀长度+1,来作为光标的指示标志


如果将这么一组数存储到数组中,便可以实现模式串任意一个位置失配,滑动的距离(既光标重新指向的字符)

next[]数组就是存储这么一组能够决定光标重新指向(滑动的距离)的一组数据


行文至此,咱们全面了解了暴力匹配的思路、KMP算法的原理、流程、流程之间的内在逻辑联系,以及next 数组

那么,我们需要着手解决代码实现

直接上代码

首先实现getnext

void GetNext(char* p,int next[])  
{  
    int pLen = strlen(p);  
    next[0] = -1;  
    int k = -1;  
    int j = 0;  
    while (j < pLen - 1)  
    {  
        //p[k]表示前缀,p[j]表示后缀  
        if (k == -1 || p[j] == p[k])   
        {  
            ++k;  
            ++j;  
            next[j] = k;  
        }  
        else   
        {  
            k = next[k];  
        }  
    }  
}

到这,你可能又迷了。这代码啥意思啊,怎么和我想象的不太一样,别急,继续往下看

db23171c2afea3d9d33003449d472e6d_0d7e2ce6901eb7dcefc773d3a193e16b.png

从上表,你可以跟着一步一步来,就会发现其中奥秘;

接下来,给出kmp算法

int KmpSearch(char* s, char* p)  
{  
    int i = 0;  
    int j = 0;  
    int sLen = strlen(s);  
    int pLen = strlen(p);  
    while (i < sLen && j < pLen)  
    {  
        //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++      
        if (j == -1 || s[i] == p[j])  
        {  
            i++;  
            j++;  
        }  
        else  
        {  
            //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]      
            //next[j]即为j所对应的next值        
            j = next[j];  
        }  
    }  
    if (j == pLen)  
        return i - j;  
    else  
        return -1;  
}  


对next的改进


先找缺陷

0c77e25babe2577d2db070ad7ba6bd38_44fe11c6c6a486f25a37ec47b5a85a8c.png

显然,当我们上边的算法得到的next数组应该是[ -1,0,0,1 ]

所以下一步我们应该是把j移动到第1个元素咯:

6bf593f92defa882545f84bfa22f5361_116f39c632f5b80ca04351754532211c.png


不难发现,这一步是完全没有意义的。因为后面的B已经不匹配了,那前面的B也一定是不匹配的,同样的情况其实还发生在第2个元素A上。

显然,发生问题的原因在于t[j] == t[next[j]]。

void Getnext(int next[],String t)
{
   int j=0,k=-1;
   next[0]=-1;
   while(j<t.length-1)
   {
      if(k == -1 || t[j] == t[k])
      {
         j++;k++;
         if(t[j]==t[k])//当两个字符相同时,就跳过
            next[j] = next[k];
         else
            next[j] = k;
      }
      else k = next[k];
   }
}


本文对b站天勤率辉

https://blog.csdn.net/dark_cy/article/details/88698736多有借鉴


还有的是对代码的解释有点太少(基本没有),原因是自己对代码理解不太够,半知半解。不敢乱讲,原理懂了,代码很是神奇,有点迷,希望大神能够给一份详细的注释和解释,多谢,欢迎讨论。



相关文章
|
5月前
|
算法
数据结构中的KMP算法及其改进算法
KMP算法通过引入部分匹配表,有效避免了重复计算,从而将字符串匹配的时间复杂度降低到O(m+n)。通过进一步优化next数组,KMP算法的效率得到了进一步提升。对于大规模字符串匹配问题,KMP算法及其改进算法提供了高效的解决方案,是计算机科学领域的经典算法之一。
86 3
|
1月前
|
算法
第四章 KMP算法理论基础
第四章 KMP算法理论基础
19 0
|
1月前
|
算法
KMP算法
KMP算法
33 0
|
3月前
|
算法 C++
A : DS串应用–KMP算法
这篇文章提供了KMP算法的C++实现,包括计算模式串的next数组和在主串中查找模式串位置的函数,用于演示KMP算法的基本应用。
|
4月前
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
123 1
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
3月前
|
算法
KMP算法
KMP算法
29 0
|
4月前
|
算法 Java
KMP算法详解及其在字符串匹配中的应用
KMP算法详解及其在字符串匹配中的应用
|
5月前
|
人工智能 算法 BI
一篇文章讲明白KMP算法(俗称看毛片算法)
一篇文章讲明白KMP算法(俗称看毛片算法)
58 0
|
5月前
|
算法 Java
Java数据结构与算法:字符串匹配算法之KMP算法
Java数据结构与算法:字符串匹配算法之KMP算法
|
6月前
|
算法
下一篇
无影云桌面