KMP 算法

简介: KMP 算法

KMP 算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速的匹配的目的.具体实现是通过一个next() 函数来实现的,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)


KMP 和 BF 唯一不一样的地方在,主串的i并不会回退,并且 j 也不会移动到 0 号位置


举例:

引出 next 数组

KMP的精髓就是 next 数组:也就是用 next[ j ]=k 来表示,不同的 j 来对应一个K值,这个K就是你将来要移动的 j要移动的位置。

而K 的值是这样求得:

1. 找到匹配成功部分的两个相等的真子串(不包含本身),一个以下标0开始,另一个以 j -1下标结尾。

2. 不管什么数据 next [ 0 ] =-1;next[ 1 ]=0;k就等于真子串的长度。

求 next数组的练习:


练习1:举例对于“ababcabcdabcde",求其的 next 数组


-1 0 0 1 2 0 1 2 0 0 1 2 0 0


练习2:再对”abcabcabcabcdabcde", 求其的 next 数组


-1 0 0 0 1 2 3 4 5 6 7 8 9 0 1 2 3 0

代码实现:

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: zhao3
 * Date: 2023-08-18
 * Time: 13:38
 */
 
public class Main {
    /**
     * 创建next 数组 
     * @param: next
     * @param: sub
     * @return: void
     * @Author: zsl
     **/    
    public static void getNext(int[] next,String sub){
        int len=sub.length();
        if(len==0){
            return;
        }
        if(len>0){
            next[0]=-1;
        }
        if(len>1){
            next[1]=0;
        }
        int k=0;
        int i=2;
        while(i<sub.length()) {
            if (k == -1 || sub.charAt(k) == sub.charAt(i - 1)) {
                next[i] = k + 1;
                k++;
                i++;
            } else {
                k = next[k];
            }
        }
    }
    /**
     * @param: str 主串
     * @param: sub 子串
     * @param: pos 主串匹配的起始位置
     * @return: void
     * @Author: zsl
     **/
    public static int KMP(String str,String sub,int pos){
        int i=pos;
        int j=0;
        int lens= str.length();
        int lensub=sub.length();
        int[] next=new int[sub.length()];
        getNext(next,sub);
        while (i<lens&&j<lensub){
            if(j==-1||str.charAt(i)==sub.charAt(j)){
                i++;
                j++;
            }else {
                j=next[j];
            }
        }
        if(j==lensub)
        return i-j;
        return 0;
    }
    public static void main(String[] args) {
        System.out.println(KMP("abcabcdefabc", "bcf", 0));
    }
}

next 数组优化

对aaaaaaaaaab next数组为[-1,0,1,2,3,4,5,6,7,8,0]

当我们在主串与子串匹配时

while (i<lens&&j<lensub){
    if(j==-1||str.charAt(i)==sub.charAt(j)){
        i++;
        j++;
    }else {
        j=next[j];
    }
}

当子串的下标为9,且与主串不匹配时,就会回退,但此时我们会发现,由于j每次回退的位置对应的字符与初始时的字符相同,大大增加了时间复杂度,因此我们可以将其优化为nextval 数组,当我们在创建nextval 数组时:

while(i<sub.length()) {
     if (k == -1 || sub.charAt(k) == sub.charAt(i - 1)) {
          next[i] = k + 1;
          k++;
          i++;
     }else {
          k = next[k];
     }
}

当 k回退后,再次匹配 sub.charAt(k) == sub.charAt(i - 1)成功后,我们需要再次判定 next[i]==next[k+1]? 如果相等,就继续回退,直到 next[i]!=next[k+1]或k==-1.


nextval 的实现:


while(i<sub.length()) {
    if (k == -1 || sub.charAt(k) == sub.charAt(i - 1)) {
         next[i] = k + 1;
         k++;
         i++;
    } else {
         while (sub.charAt(k)!=sub.charAt(i-1)||sub.charAt(i)==sub.charAt(k+1)) {
             k = next[k];
             if(k==-1){
                 break;
             }
         }
    }
}
相关文章
|
5月前
|
算法
数据结构中的KMP算法及其改进算法
KMP算法通过引入部分匹配表,有效避免了重复计算,从而将字符串匹配的时间复杂度降低到O(m+n)。通过进一步优化next数组,KMP算法的效率得到了进一步提升。对于大规模字符串匹配问题,KMP算法及其改进算法提供了高效的解决方案,是计算机科学领域的经典算法之一。
81 3
|
1月前
|
算法
第四章 KMP算法理论基础
第四章 KMP算法理论基础
18 0
|
1月前
|
算法
KMP算法
KMP算法
25 0
|
3月前
|
算法 C++
A : DS串应用–KMP算法
这篇文章提供了KMP算法的C++实现,包括计算模式串的next数组和在主串中查找模式串位置的函数,用于演示KMP算法的基本应用。
|
4月前
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
117 1
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
3月前
|
算法
KMP算法
KMP算法
26 0
|
4月前
|
算法 Java
KMP算法详解及其在字符串匹配中的应用
KMP算法详解及其在字符串匹配中的应用
|
5月前
|
人工智能 算法 BI
一篇文章讲明白KMP算法(俗称看毛片算法)
一篇文章讲明白KMP算法(俗称看毛片算法)
55 0
|
5月前
|
算法 Java
Java数据结构与算法:字符串匹配算法之KMP算法
Java数据结构与算法:字符串匹配算法之KMP算法
|
22天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。