【算法学习笔记】 Notes of Algorithm —— KMP算法

KMP算法



KMP 介绍

  • KMP 算法是一种改进的字符串匹配算法;

  • 算法核心是利用匹配失败后的信息,尽量减少模式串和文本串的匹配次数,以达到快速匹配的目的;

  • 算法的时间复杂度为 O ( m + n ) O(m + n) O(m+n),而暴力破解的时间复杂度为 O ( m n ) O(mn) O(mn)

  • 区别于暴力破解,KMP 在匹配过程中,如果出现错误的字符,会先判断文本串和模式串的是否有相同的最大相等前缀,并将指针移动到该前缀的末尾,然后继续匹配判断;这样的操作,可以有效减少匹配的次数;

  • 案例一:在这里插入图片描述

    在这里插入图片描述

  • 案例二:
    在这里插入图片描述

    在这里插入图片描述

KMP的匹配表

  • 前缀:包含首字母但不包含尾字母的所有字符串;
  • 后缀:包含尾字母但不包含首字母的所有字符串;

在这里插入图片描述

  • 上图中,我们逐步获取该模式串的匹配值:
    • A:0;
    • AB:0;
    • ABC:0;
    • ABCA:1;
    • ABCAB:2;
  • 最后得到该模式串的匹配表:

在这里插入图片描述

匹配表获取

  • 构建匹配表 n e x t next next 的代码分为四个步骤:

    • 初始化;
    • 前缀末尾 与 后缀末尾 不一致的情况;
    • 前缀末尾 与 后缀末尾 一致的情况;
    • 更新匹配表 n e x t next next
  • //初始化,其中 m 是模式串的长度;
    vector<int> next(m);
    next[0] = 0;
    //i有代表后缀末尾,j有代表前缀末尾;
    //后缀要与前缀比较,故从索引 1 开始;
    for (int i = 1, j = 0; i < m; ++i) {
        //当出现不一致情况时,需要前缀末尾回退,当前j回退到索引next[j-1]处;
        //如果j=0,正处于模式串首字符,不需要回退,故从 j = 1开始判断;
        //此处应该用while循环,而不是for循环,因为回退后并不保证会出现一致情况;
    	while (j > 0 && needle[i] != needle[j]) j = next[j - 1];
        //当出现一致情况后,说明当前缀与后缀相等,故加长相等缀的长度;
    	if (needle[i] == needle[j]) ++j;
        //操作完成后,最后更新匹配表信息;
    	next[i] = j;
    }
    

匹配表使用

  • 在得到模式串的匹配表后,可以通过匹配表在任何文本串中,进行字符串匹配,这是个通用的表;

  • //n为文本串haystack的长度,m为模式串needle的长度;
    //i为文本串的指针,j为模式串的指针;
    for (int i = 0, j = 0; i < n; ++i) {
        //如果当前字符不匹配,则将j移动到最长相等前缀的末尾处;
    	while (j > 0 && haystack[i] != needle[j]) j = next[j - 1];
        //如果字符匹配,则继续匹配模式串的下一个字符;
    	if (haystack[i] == needle[j]) ++j;
        //如果j到达模式串的末尾,说明找到匹配字符串,返回;
    	if (j == m) return i - m + 1;
    }
    return -1;
    

案例

  • 描述:实现 s t r S t r ( ) strStr() strStr() 函数;给两个字符串 h a y s t a c k haystack haystack n e e d l e needle needle,请在 h a y s t a c k haystack haystack 字符串中找出 n e e d l e needle needle 字符串出现的第一个位置(下标从 0 开始);如果不存在,则返回 -1;如果 n e e d l e needle needle 是空字符串,应当返回 0; 0 ≤ h a y s t a c k . l e n g t h ,   n e e d l e . l e n g t h ≤ 5 ∗ 1 0 4 0 \leq haystack.length,\ needle.length \leq 5 * 10^4 0haystack.length, needle.length5104 h a y s t a c k haystack haystack n e e d l e needle needle 仅由小写英文字母组成;
class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size(), m = needle.size();
        if (!m) return 0;
        vector<int> next(m);
        next[0] = 0;
        for (int i = 1, j = 0; i < m; ++i) {
            while (j > 0 && needle[i] != needle[j]) j = next[j - 1];
            if (needle[i] == needle[j]) ++j;
            next[i] = j;
        }
        for (int i = 0, j = 0; i < n; ++i) {
            while (j > 0 && haystack[i] != needle[j]) j = next[j - 1];
            if (haystack[i] == needle[j]) ++j;
            if (j == m) return i - m + 1;
        }
        return -1;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值