KMP算法

KMP算法是一种用于优化字符串匹配的算法。

文章目录

一、KMP算法是什么?

二、前缀表与Next数组

1.前缀表

2.Next数组

3.通过Next数组进行字符串匹配

4.代码实现

字符串匹配的整体代码实现:

总结


一、KMP算法是什么?

        KMP算法是一种字符串匹配算法,可以在 O(n+m) 的时间复杂度内实现两个字符串的匹配。其主要思想是当出现字符串不匹配时,通过之前记录的已经匹配的文本信息,直接跳过不可能的字符串匹配,避免重新匹配。

二、前缀表与Next数组

1.前缀表

       前缀表的作用是跳过不可能成功的字符串匹配,并进行回退,其回退的位置是通过Next数组来操作的。

2.Next数组

       Next数组就是一个前缀表,在字符串匹配问题中,我们的目的是寻找在主串 s 中是否存在模式串 t 若存在的话,其出现的位置在哪?而Next 数组就是用于模式串 t的,其元素 next[i] 表示 t[0] ~ t[i] 这一个子串中,最长的公共前后缀的长度。

例如在模式串baabaa中,Next数组的长度为模式串的长度,初始化Next [ 0 ] = 0,其余元素如下图所示,红色代表最长公共前后缀。

下方箭头表示 ,初始化为1,上方箭头 表示后缀的结尾位置,上下箭头索引对应的字符不相同,由图看出从i到j的子串中无公共前后缀,所以Next [1] = 0,上箭头 j 不移动;

下箭头 i 向右移动,此时情况同上,故Next [2] =0,上标不移动;

 下箭头继续向右,上下箭头索引对应的字符相同,此时存在公共前后缀 b,因此 Next [3] =j +1 =1,上标将会右移;

 此时下箭头移动后,上下箭头索引对应的字符相同,存在的最长公共前后缀为ba,因此Next [4]继续+1=2,上箭头继续右移;

 此时下箭头移动后,上下箭头索引对应的字符相同,存在的最长公共前后缀为baa,因此Next [5]继续+1=3,上箭头继续右移;此时上箭头索引为3,下箭头索引为6,当不相等时,上箭头会持续左移,直到上下箭头索引对应的字符相同,最终next [6]=3

 Next[] ={0,0,0,1,2,3,3}

3.通过Next数组进行字符串匹配

 如图所示,当匹配到模板串的尾字母a时,出现了不匹配的情况,此时将通过Next数组中尾字母a对应的索引,从该索引处重新匹配(该索引之前的字符无需重新匹配);

 重新匹配的情况如图所示,此时情况同上出现了尾字母不匹配的情况,继续根据Next数组进行回退,

 此时进行了成功匹配。

4.代码实现

Next数组的实现,其Java代码如下所示:

private void getNext(int[] next , String s ){
    int j = 0;
    next[0] = 0;
    for (int i = 0; i < s.length(); i++){
        while ( j > 0 && s.charAt(i) != s.charAt(j))
            j = next[j-1];
        if (s.charAt(j) == s.charAt(i))
            j++;
        next[i] = j;
    }
}

字符串匹配的整体代码实现:

其中 s 表示主串 ,t表示模板串,当成功匹配时,将返回匹配成功开始时的下标,否则将返回false,表示s中不存在t。

class Solution {
    private  void getNext(int[] next , String s ){
        int j = 0;
        next[0] = 0;
        for (int i = 0; i < s.length(); i++){
            while ( j > 0 && s.charAt(i) != s.charAt(j))
                j = next[j-1];
            if (s.charAt(j) == s.charAt(i))
                j++;
            next[i] = j;
        }
    }
    public int strStr(String s, String t) {
        if (t.length() == 0) return 0;
        int[] next = new int[t.length()];
        getNext(next, t);

        int j = 0;
        for (int i = 0; i < s.length(); i++){
            while (j > 0 && t.charAt(j) != s.charAt(i))
                j = next[j-1];
            if (t.charAt(j) == s.charAt(i))
                j++;
            if (j == t.length())
                return i-t.length()+1;
        }
        return -1;
    }
}

总结

Next数组计算的形式有很多,有的会对数组进行整体左移,有的则会进行减1操作,但其根本的思想是一致的,对于字符串匹配问题,引入KMP算法能大大降低问题的时间复杂度。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面我来为您讲解使用KMP算法解决字符串匹配问题的方法。 KMP算法是一种比较高效的字符串匹配算法,它的核心思想是利用已经匹配过的信息,尽可能减少不必要的字符比较次数,从而提高匹配效率。具体实现时,KMP算法利用前缀和后缀的概念,对于每个字符,计算出它的最长前缀和最长后缀的匹配长度,然后根据这些信息来移动模式串,从而减少比较次数。 下面是使用KMP算法解决字符串匹配问题的代码实现: ```python def str_str(s, n): if not n: return 0 if not s: return -1 m, k = len(s), len(n) next = get_next(n) i = j = 0 while i < m and j < k: if j == -1 or s[i] == n[j]: i += 1 j += 1 else: j = next[j] if j == k: return i - k else: return -1 def get_next(n): k, j = -1, 0 next = [-1] * len(n) while j < len(n) - 1: if k == -1 or n[k] == n[j]: k += 1 j += 1 next[j] = k else: k = next[k] return next ``` 需要注意的是,KMP算法中的next数组表示的是模式串中每个位置的最长前缀和最长后缀的匹配长度,而不是暴力匹配算法中的每个位置的最长前缀和最长后缀。因此,KMP算法中的next数组需要先计算出来,然后再根据它来移动模式串。 接下来,我来给您提供一组测试用例,证明KMP算法的正确性: ```python assert str_str("hello", "ll") == 2 assert str_str("aaaaa", "bba") == -1 assert str_str("mississippi", "issip") == 4 ``` 这些测试用例可以验证KMP算法的正确性。相比暴力匹配算法KMP算法的时间复杂度为O(m+n),可以在较短的时间内解决字符串匹配问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值