KMP 템플릿 매칭 알고리즘 - KMP를 얻기 위해 여섯 단계

KMP 알고리즘 - KMP를 얻기 위해 여섯 단계

1. 무엇 KMP입니다

KMP 알고리즘은 KMP 템플릿 매칭 알고리즘이라고 누스-Morria-프랫 알고리즘이라고 DEKnuth, J, H, 모리스 협찬 VRPratt 세 족장이다. 존경 브 루트 포스 (폭력) 알고리즘이 알고리즘은 상대적으로 큰 개선을 중심으로 시간의 효율성을 향상시킬 수있는 주요 문자열 포인터 등을 제거있다. (시간위한 공간)

2.KMP 간단한 템플릿 매칭 (전수)

폭력 브 루트 포스

이 비교를 통해 슈퍼 간단한 스테핑입니다. . . .
문자열을 감안할 때 S, T , TS 한 최초의 길이 T 비교 문자열로는, 성공적으로 첫 번째 인덱스 매칭 반환 경기 계속 실패 S를 다음의 길이 T 같은 단어 문자열 ......의 각각의 반복을 통해 길이 T 동일한 문자열과 일치하는 이 시간 복잡성 (N * m) O이다.




그림 삽입 설명 여기
그림 삽입 설명 여기

KMP 템플릿 매칭 알고리즘 - CAN 구현 복잡도 O (m + n)의

첫 번째 단계는 : 접두사와 접미사 어떤 문자열 이해하기
그림 삽입 설명 여기 : 같은
ABC해야합니다 - abcjkdabc, 배열과 같은 가장 긴 접미사의 다음 가장 긴 접두사.
cbcbc, 같은 긴 접두사와 접미사 긴 -이다 CBC.
abcbc, 접두사와 접미사 동일한 최대의 긴, 그것은 존재하지 않습니다.
긴 접두사를 참고 : 첫 번째 문자는 시작했다,하지만 마지막 문자가 포함되어 있지 않습니다.

第二步,理解关于字符串匹配的规则
假设S与T要进行匹配,匹配规则如图
그림 삽입 설명 여기
这里aba就是最长前缀字串,然后下一次a是最长前缀字串
그림 삽입 설명 여기
借别人的图示意:

그림 삽입 설명 여기

第三步,如何得出j的更新规则——即计算next数组
我看了数据结构(java)第四版,讲的很好。
公式:그림 삽입 설명 여기
例子演示:
그림 삽입 설명 여기
第四步,上计算next数组的代码

int get_next(string t,int * next) {
    //先定义一个数组
    int length = t.length();
    int j=0,k=-1;
    next[0] = -1;
    while(j<length-1)//因为我们是在找最长前缀字串,这里得减一。
        if(k==-1||t[j]==t[k]) { //当前的字串最新的字符相等或者字串总长度1
            k++;
            j++;//比较下一个字符
            next[j] = k;//最长前缀字串记录下来,因为前面的k,j都加了1

        } else
            k = next[k];//重新在k长度的前缀字串找当前j长度字串的最长前缀字串,更新索,听说这里是最难理解的
    return 1;
}

第五步,理解 k = next[k]
k = next[k];//重新在k长度的前缀字串找当前j长度字串的最长前缀字串,
这里我给例子演示,反正我是一下子就理解了。
그림 삽입 설명 여기
图示:因为p5!=p11,这个时候,最长前缀字串肯定不会比上次的大了,不可能是6,我们只能重新寻找,而重新寻找的规则就是k = next[k]=2
그림 삽입 설명 여기
第六步,最后一步,上匹配字串的代码

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
//建立next数组
int get_next(string t,int * next) {
    //先定义一个数组
    int length = t.length();
    int j=0,k=-1;
    next[0] = -1;//这里是为了
    while(j<length-1)//因为我们是在找最长前缀字串,这里得减一。
        if(k==-1||t[j]==t[k]) { //当前的字串最新的字符相等或者字串总长度1
            k++;
            j++;//比较下一个字符
            next[j] = k;//最长前缀字串记录下来

        } else
            k = next[k];//重新在k长度的前缀字串找当前j长度字串的最长前缀字串,更新索
    return 1;
}
int compare_str(string s,string t,int pos) {
    int n=s.length();
    int m = t.length();
    if(n<m||pos>=n||n==0) { //不合理的输入
        return 0;
    }
    if(pos<=0) {
        pos=0;//提高容错率
    }
    int next[m];
    //生成next数组
    get_next(t,next);
    int i=pos,j=0;
    while(i<n&&j<m)
        if(j==-1||s[i]==t[j]) { //当前匹配成功,继续匹配下一个字符
            i++;
            j++;
        } else { //i是不回溯,匹配规则更新匹配的j
            j = next[j];//这里就是我们说的匹配规则
            if(n-i+1<m-j+1)//剩下的字串不够t的长度,就不用比较了
                break;
        }

    if(j==m)
        return i-j;//成功匹配。,返回对应的索引
    return -1;//否则退出

}
int main() {
    string t,s;
    cin>>s;
    cin>>t;
    int pos =compare_str(s,t,0);
    cout<<pos;
    return 0;
}

更新改进KMP算法。

그림 삽입 설명 여기
现在我们比较的是C和B,不匹配。
显然,当我们上边的算法得到的next数组应该是[ -1,0,0,1 ]
所以next[3] = 1。下一步的匹配:明显我们又来比较C和B,这是是多余的
所以我们应该改进计算next数组匹配
그림 삽입 설명 여기
改进的算法 就是避免这种情况,代码演示

int get_next(string t,int * next) {
    //先定义一个数组
    int length = t.length();
    int j=0,k=-1;
    next[0] = -1;
    while(j<length-1)//因为我们是在找最长前缀字串,这里得减一。
        if(k==-1||t[j]==t[k]) { //当前的字串最新的字符相等或者字串总长度1
            k++;
            j++;//比较下一个字符
            //使用改进的算法
            if(t[j]!=t[k])
                next[j] = k;//最长前缀字串记录下来
            else next[j] = next[k];//直接跳到上次找到的后缀字串,改进的代码结束

        } else
            k = next[k];//重新在next[k]长度的前缀字串找当前j长度字串的最长前缀字串,更新索引
    return 1;
}

그림 삽입 설명 여기
참고 블로그
https://blog.csdn.net/dark_cy/article/details/88698736
:
https://blog.csdn.net/starstar1992/article/details/54913261?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source= distribute.pc_relevant.none-작업

게시 50 개 원래 기사 · 원의 찬양 (24) · 전망 2358

추천

출처blog.csdn.net/qq_44861675/article/details/104532051