算法学习-KMP(字符串匹配)解释

KMP算法

BF算法

BF算法就是我们最基本的求解字符串匹配的算法,算法的时间复杂度为O(M*N),空间复杂度为O(1),具体过程如下:

第一次 第二次 第三次 第四次
模式串S[i] abcababc abcababc abcababc abcababc
匹配串T[j] ababc ababc ababc ababc

可以看到在第三次匹配失败的时候,我们要回溯,直接S串直接i+=1,然后T串j=0从头继续开始。这样复杂度就比较高了。

KMP算法

而KMP算法就是为了解决BF算法的复杂度比较高而出现的,KMP算法的时间复杂度为O(M+N),空间复杂度为O(N),具体过程如下:

第一次 第二次 第三次 第四次
模式串S[i] abaababc abaababc abaababc abaababc
匹配串T[j] ababc ababc ababc ababc
第四次 第五次 第六次 第七次 第八次
abaababc abaababc abcababc abcababc abcababc
ababc ababc ababc ababc ababc

在第四次匹配失败后,不进行回溯,而是直接对匹配串进行下一个匹配,是因为前面已经把aba匹配过了,知道前一个也是a不需要再次进行匹配,这个就是通常所说的KMP算法。而在匹配失败后到底对哪个进行再次匹配,也就需要我们求next[j]数组了。

求next数组

next数组存放的是,当匹配失败后,需要跳转到哪个字符再次进行匹配。

求的方法,手算:

例子(ababc)的next数组为:[-1 0 0 1 2].



i = 0, j=-1, next[0]=-1, next[1]=0;



next[2] = next[1+1];

next[1] = 0

T[1] != T[0];

则next[2] = next[1] = 0;



next[3] = next[2+1];

next[2] = 0;

T[2] == T[0] (T[2] = a, T[1] = b)

则next[3] = next[2]+1;



next[4] = next[3+1];

next[3] = 1;

T[3] == T[1];

则next[4] = next[3]+1 = 2;

以上是手算的解法,代码求解比较简单。

如下

void getNextval(char *p,int *next)
{
    int j,k;
    next[0]=-1;
    j=0;
    k=-1;
    while(j<strlen(p)-1)
    {
        if(k==-1||p[j]==p[k])    //匹配的情况下,p[j]==p[k]
        {
            j++;
            k++;
            next[j]=k;
        }
        else                   //p[j]!=p[k]
            k=next[k];
    }
}

改进后的next数组

改进的之后的next数组效率更高,但是我暂时还没找到如何手算,假如你知道,请评论给我,非常感谢。但是代码实现非常简单,就是在第一次判断之后,再进行一次判断。

代码如下:

void getNext(char *str, int *next){
    int i = 0;
    int length = (int)strlen(str);
    int j = -1;
    next[0] = -1;
    while (i < length-1) {
        if (j == -1 || str[i] == str[j]) {
            ++i;
            ++j;
            if (str[i] != str[j]) {
                next[i] = j;
            }else{
                next[i] = next[j];
            }
        }else{
            j = next[j];
        }
    }
}

KMP代码实现

而KMP整个的代码实现如下:

int KMP(const char *src, const char *tar, int *next){
    int srcLength = (int)strlen(src);
    int tarLength = (int)strlen(tar);
    int i = 0, j = 0;
    while (i < srcLength && j < tarLength) {
        if (j == -1 || src[i] == tar[j]) {
            ++i;
            ++j;
        }else{
            j = next[j];
        }
    }
    if (j >= tarLength) {
        return i-tarLength;
    }else{
        return -1;
    }
}
时间: 2024-11-05 22:57:40

算法学习-KMP(字符串匹配)解释的相关文章

算法模板——KMP字符串匹配

功能:输入一个原串,再输入N个待匹配串,在待匹配串中找出全部原串的起始位置 原理:KMP算法,其实这个东西已经包含了AC自动机的思想(fail指针/数组),只不过适用于单模板匹配,不过值得一提的是在单模板大量匹配待匹配串时,这个会有相当大的优势,AC自动机虽然好想一些,但是在这一类问题上的性价比就略低了 1 var 2 i,j,k,l,m,n:longint; 3 a:array[0..100000] of longint; 4 s1,s2:ansistring; 5 begin 6 readl

Luogu P3375 【模板】KMP字符串匹配

P3375 [模板]KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整数

洛谷P3375 [模板]KMP字符串匹配

To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整

算法学习 - 树的一些解释

树的解释 树是ADT里面很经典的数据结构了,应用太多了,相对于链表的线性访问时间,O(n).树的大部分操作的平均运行时间都是为O(logN). - 树的概念 树有几种方式定义,一种是递归,若树不为空,则一棵树是由根(root)的节点r和0个或者多个非空树组成.N个节点的树,有N-1个边.没有儿子的节点称为叶子(leaf). 对于任意节点N(i),它的深度为从根节点到N(i)的唯一路径长度.如果存在N(1)到N(2)的路径,那么N(1)是N(2)的祖先.如果N(1)不等于N(2),那么就称为真祖先

KMP字符串匹配

1 #include<iostream> 2 3 4 using namespace std; 5 6 #define MAX 255 7 8 typedef unsigned char BYTE; 9 10 typedef BYTE String[MAX+1]; 11 12 bool strAssign(String& strTemp,char* Temp); //定长字符串存储 13 bool strTravel(String& strTemp); //打印 14 void

P3375 模板 KMP字符串匹配

P3375 [模板]KMP字符串匹配 来一道模板题,直接上代码. #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e6 + 5; int n, m; char s1[N], s2[N]; int nxt[N] ; void Get_next(char *s) { int j, L = strlen(s + 1); nxt[1] = j = 0; for(int i = 2; i

算法题之字符串匹配问题

我最近复习一道困难程度的算法题,发现了许多有趣之处.在借鉴了他人解法后,发现从最简单的情况反推到原题是一种解锁新进阶的感觉.从递归到动态规划,思维上一步一步递进,如同一部跌宕起伏的小说,记录下来和诸君共赏之. 题目如下: 给你一个字符串?s?和一个字符规律?p,请你来实现一个支持 '.'?和?'*'?的正则表达式匹配. '.' 匹配任意单个字符 '*' 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖?整个?字符串?s的,而不是部分字符串. 说明: s?可能为空,且只包含从?a-z?的小写字母

洛谷—— P3375 【模板】KMP字符串匹配

题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整数,表示前缀数组next[i]的值. 输

P3375 【模板】KMP字符串匹配(全程注释,简单易懂)

题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了. 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包含一个整数,表示s2在s1中出现的位置 接下来1行,包括length(s2)个整数,表示前缀数组next[i]的值. 输