c++ KMP字符串匹配算法

 更新时间:2022年01月11日 08:38:32   作者:按时吃早饭的ju  
大家好,本篇文章主要讲的是c++ KMP字符串匹配算法,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下

KMP算法简介

        KMP算法(Knuth-Morris-Pratt 算法)是一个著名的字符串匹配算法,它主要的思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配。

        本章以力扣 28. 实现 strStr()为例子进行讲解。

        力扣28.实现strStr()函数:给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回  -1 。

        说明:当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。对于本题而言,当 needle 是空字符串时我们应当返回 0 。

        示例 1: 输入:haystack = "hello", needle = "ll"        输出:2

  此题若用暴力解法代码如下:

class Solution {
public:
    int strStr(string haystack, string needle) {
        int n=haystack.size(),m=needle.size();
        if(m==0) return 0;
        for(int i=0;i<n;i++){
            if(haystack[i]==needle[0]){
                for(int j=0;j<m;j++){
                    if(haystack[i+j]!=needle[j])
                        break;
                    if(j==m-1) return i;
                }
            }
        }
        return -1;
    }
};

         可见暴力匹配过程中实现的是一个双层循环,那么算法的时间复杂度较高,为О(n*m),然而KMP的算法时间复杂度仅为О(n+m),其算法性能明显提高,具体时间复杂度计算方法后面介绍。

前缀表

        KMP算法中一个重要的概念就是前缀表(prefix table),并用一维数组 next 记录前缀信息实际上next数组就是一个前缀表。

        了解前缀表我们首先需要了解前缀和后缀的区别,此处的前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串,后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。比如字符串“abac”的前缀有“a”, "ab”, "aba”,字符串“abac”的后缀有“c”,"ac”,"bac”。

        前缀表第 i 个位置存的值 next[i] 代表[0,i]这个字符串最长的相同前后缀的长度,比如字符串“abbc”的 next[3]为 0 ,next[2]为 1 ("aba”的前缀有“a”, "ab”,后缀有“a”,"ba”)。

        前缀表的作用是用来记录了模板串与主串(文本串)不匹配的时候,模板串应该从哪里开始重新匹配。

        KMP算法的核心思想就是先求出匹配模板的next数组,再运用next数组进行字符串匹配。  

如何构造前缀表next数组

void get_next(int *next,string t){ //t为模板字符串
        //定义两个指针prefix和suffix,prefix指向前缀起始位置,suffix指向后缀起始位置
        int prefix=0;
        next[prefix]=0;
        for(int suffix=1;suffix<t.size();suffix++){
            while(prefix>0 && t[suffix]!=t[prefix]){//前后缀不相同,前缀指针向前回退
                prefix=next[prefix-1];
            }
            if(t[suffix]==t[prefix]){//前后缀相同,前缀指针前进一位
                prefix++; 
            }
            next[suffix]=prefix;//更新next数组,prefix走到哪说明就有多少的相同的前后缀
        }
    }

如何用next数组进行模板匹配

int strStr(string haystack, string needle) {
        if(needle.size()==0) return 0;
        int next[needle.size()];
        get_next(next,needle);
        int j=0;
        //定义两个下标j指向模版串起始位置,i指向文本串起始位置
        for(int i=0;i<haystack.size();i++){
            while(j>0 && haystack[i]!=needle[j]){ //模版串j位置和文本串i位置不相同,j利用next数组回退到上一个相同的位置继续匹配
                j=next[j-1];
            }
            if(haystack[i]==needle[j]){  //模版串j位置和文本串i位置相同
                j++;
            }
            if(j==needle.size()){  //找到匹配的字符串
                return (i-needle.size()+1); //返回匹配的字符串起始位置
            }
        }
        return -1;
    }

由此可见构造next数组的时间复杂度是О(m),利用next数组进行匹配的时间复杂度是О(n),总的时间复杂度是О(n+m)

总结

到此这篇关于c++ KMP字符串匹配算法的文章就介绍到这了,更多相关c++ KMP字符串匹内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • QSS样式表实现界面换肤功能

    QSS样式表实现界面换肤功能

    这篇文章主要介绍了QSS样式表实现界面换肤功能,对QSS样式表进行简单介绍,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-10-10
  • C++实现学生选课系统

    C++实现学生选课系统

    这篇文章主要为大家详细介绍了C++实现学生选课系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02
  • 可能是你看过最全的十大排序算法详解(完整版代码)

    可能是你看过最全的十大排序算法详解(完整版代码)

    排序算法是程序中常用的算法,下面这篇文章主要给大家介绍了关于十大排序算法的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • C++继承与菱形继承详细介绍

    C++继承与菱形继承详细介绍

    继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程
    2022-08-08
  • QT .pro文件使用解析

    QT .pro文件使用解析

    QT工程的pro文件,在创建工程时由QTCreater自动创建,我们可以往里面添加内容,增加库文件的声明,包含路径、预处理器定义,生成目录,输出中间目录等等设置,本文就来介绍一下
    2022-04-04
  • C语言大厂面试技巧及strcpy()函数示例详解

    C语言大厂面试技巧及strcpy()函数示例详解

    这篇文章主要为大家介绍了C语言面试技巧,以strcpy()函数为示例进行分析详解,有需要冲刺大厂的朋友们可以借鉴参考下,希望能够有所帮助
    2021-11-11
  • c语言实现足球比赛积分统计系统

    c语言实现足球比赛积分统计系统

    这篇文章主要为大家详细介绍了c语言实现足球比赛积分统计系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • C语言:自定义类型详解

    C语言:自定义类型详解

    这篇文章主要介绍了C语言自定义函数详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-09-09
  • QT编写地图实现离线轮廓图的示例代码

    QT编写地图实现离线轮廓图的示例代码

    这篇文章主要介绍了在利用QT编写地图时常常需要用到的离线轮廓图,离线轮廓图使用起来比线轮廓图麻烦一点,需要自己绘制。感兴趣的小伙伴可以学习一下
    2021-12-12
  • C++ 用红黑树模拟实现set、map的示例代码

    C++ 用红黑树模拟实现set、map的示例代码

    set、map的底层结构是红黑树,它们的函数通过调用红黑树的接口来实现,本文主要介绍了C++ 用红黑树模拟实现set、map,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03

最新评论