zoukankan      html  css  js  c++  java
  • KMP算法

    KMP算法

    字符串算法


    给定两个字符串s1和s2,求s2在s1中所有的出现位置

    暴力(O(n*m)):

    #include<bits/stdc++.h>
    using namespace std;
    string s1,s2;
    int main(){
    scanf("%s%s",s1,s2);
    int n1=strlen(s1),n2=strlen(s2);
    for(int i=1;i<=n1-n2+1;i++){
    bool pd = 0;
    for(int j=1;j<=n2;j++) if(s1[i+j-1]!=s2[j]){
    pd = 1;
    break;
    }
    if(!pd) print("%d",i+n2-1);
    }
    return 0;
    }

    正题 KMP

    整体感官

    假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置

    • 如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符;

    • 如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了j - next [j] 位。

      • 换言之,当匹配失败时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next 值,即移动的实际位数为:j - next[j],且此值大于等于1。

    原理

    利用最大的相同前缀后缀(以下记作maxsame)缩短搜索时间

    eg. A B C D A B C

          same={A B C}

    失配时可利用前后缀相同的性质将短串移动到相同前缀的后一位

    next[]

    next[]指当失配时将当前长串的匹配位与短串的何位置相对齐

    即短串当前匹配位之前所有字符组成的字符串的maxsame长度

    第一个取-1

    递归求next[]

    void getNext(){
    int len=strlen(p);
    next[0]=-1;
    int k=-1;//记忆化 存储当前已有的maxsame长度
    int j=0;//当前下标
    while(j<len-1){
    if(k==-1||p[j]==p[k]){
    ++k;
    ++j;
    next[j]=k;//把当前匹配位之前所有字符组成的字符串的maxsame长度赋给next
    }else{
    k=next[k];
    }
    }
    return;
    }

    若p[j]!=p[k],

    将k换成当前maxsame的maxsame再进行匹配

    组合到一块

    模板:P3375

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    int next[10000001];
    char s1[10000001],s2[10000001];
    void getNext(){
    int len=strlen(s2);
    next[0]=-1;
    int k=-1;
    int j=0;
    while(j<len){
    if(k==-1||s2[j]==s2[k]){
    ++k;
    ++j;
    next[j]=k;
    }else{
    k=next[k];
    }
    }
    return;
    }
    void KMP(){
    int len1=strlen(s1);
    int len2=strlen(s2);
    int i=0,j=0;
    while(i<len1&&j<len2){
    if(j==-1||s1[i]==s2[j]){
    j++;
    i++;
    }else{
    j=next[j];
    }
    if(j==len2){
    printf("%d ",i-j+1);
    j=next[j];
    }
    }
    for(int i=1;i<=strlen(s2);i++){
    printf("%d ",next[i]);
    }
    return;
    }
    int main(){
    scanf("%s%s",s1,s2);
    getNext();
    KMP();
    return 0;
    }

    P2375

    P3435

    P3426



  • 相关阅读:
    《Java程序设计》 第一周学习任务(2)
    《Java程序设计》 第一周学习任务(1)
    Git 提示fatal: remote origin already exists 解决办法
    写给小白的酸酸乳使用方法
    美國Tarrant County College
    硬盘数据恢复工具终身版
    安卓手机系统安装虚拟机
    linux网络基础
    Linux基础命令:read
    Linux shell基础
  • 原文地址:https://www.cnblogs.com/wsyunine/p/14223572.html
Copyright © 2011-2022 走看看