• 给小白看的KMP算法


    浅谈KMP算法:

    (大部分人的KMP写法都是不一样的)

    一:

      先给大家推荐一个讲kmp比较好理解的一个博客:阮一峰

    二:

     下面介绍一点相关概念:

    栗子: 
      P串: ABCBD

      前缀:A,AB,ABC,ABCB,ABCBD 
      真前缀:A,AB,ABC,ABCB 
      后缀:D,BD,CBD,BCBD,ABCBD 
      真后缀:D,BD,CBD,BCBD

    KMP算法里的next数组的含义:

    栗子: 
      P串: ABCDABD 
      next[] = {-1, 0, 0, 0, 0, 1, 2, 0, }; 
      next[i] 的含义:P串前 i 个字符(包括第 i 个)的最长真前缀后缀公共长度;     
      如 i = 5时: 
        真前缀:A,AB,ABC,ABCD 
        真后缀:BCDA,CDA,DA,A

      显而易见, 前缀和后缀相同的只有 A,而 A 的长度为 1,所以next[5] = 1;

    next数组求法:

    //用通俗的语句说就是k是用来表示子串中前k个和后k个是相同的,i是用来遍历数组
    void get_next(char *t,int lent){
        nex[0] = -1;
        for(int i = 0,k = -1;i < lent;){
            if(k==-1||t[i] == t[k]){
                ++k;++i;
                nex[i]=k;
            }else k = nex[k];
    /*如果c[i]和c[k]中字符不同说明匹配是失败,要把k的值重新退到next[ k ]
    直到两者相同才停止。这样做的好处是没必要再重新从头再来,节约时间*/
        }
    }

    简单KMP算法的实现:

    //返回主串中匹配的位置(第一个),如果不匹配返回-1;
    int kmp(char *s,char *t,int lens,int lent)
    {
        int i = 0, j = 0;
        while(i < lens&&j<lent) {
            if(j==-1||s[i] == t[j]){
                i++;j++;
                if(j==lent){
                    return i-j+1;
                }
            }else j=nex[j];
        }
        return -1;
    }

    几道例题:

    洛谷P3375:

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn = 1e6 + 10;
    int nex[maxn];
    char s[maxn],t[maxn];
    int lens,lent;
    void get_next(){
        nex[0] = -1;
        for(int i = 0,k = -1;i < lent;){
            if(k==-1||t[i] == t[k]){
                ++k;++i;
                nex[i]=k;
            }else k = nex[k];
        }
    }
        
    void kmp()
    {
        int i = 0, j = 0;
        while(i < lens&&j<lent) {
            if(j==-1||s[i] == t[j]){
                i++;j++;
                if(j==lent){
                    printf("%d
    ",i-j+1);
                    j=nex[j];
                }
            }else j=nex[j];
        }
    }
    int main(){
        while(~scanf("%s %s",s,t)){
            lens=strlen(s);
            lent=strlen(t);
            get_next();
            kmp();
            for(int i=1;i<=lent;++i){
                printf("%d%c",nex[i],i==lent?'
    ':' ');
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    限制泛型可用类型,类型通配符声明,泛型方法
    泛型简介,泛型类及使用
    异常概念和处理机制,try-catch-finally,throw和throws,自定义异常
    随机验证码
    常用类--Date日期类,SimpleDateFormat日期格式类,Calendar日历类,Math数学工具类,Random随机数类
    String、StringBuffer和StringBuilder,定义一个自己的StringBuilder的类
    自动装箱和拆箱,枚举类型
    使用内部类开发一个存放数据的容器
    手推期望、方差
    ML 徒手系列 最大似然估计
  • 原文地址:https://www.cnblogs.com/Cwolf9/p/8921469.html
Copyright © 2020-2023  润新知