zoukankan      html  css  js  c++  java
  • KMP(模板)

    算法讲解: KMP算法最浅显易懂
    模板来源: 从头到尾彻底理解KMP

    首先:KMP的模板为:

    void get_next(char *a, int *nex) {
        nex[1] = 0;
        for (int i = 2, j = 0; i <= len; i++) {
            while (j > 0 && a[i] != a[j + 1])j = nex[j];
            if (a[i] == a[j + 1])j++;
            nex[i] = j;
        }
        return;
    }
    
    int KMP(char *a, char *b) {//b为母串
        for (int i = 1, j = 0; i <= strlen(b + 1); i++) {
            while (j > 0 && (j == strlen(a + 1) || b[i] != a[j + 1]))j = nex[j];
            if (b[i] == a[j + 1])j++;
            f[i] = j;
            //若a在b中出现,,返回出现的位置
            //if(f[i]==strlen(a+1)){return i-strlen(a);}
        }
        return 1;
    }

    例题:2018 UESTC Training for Search Algorithm & String——L主楼

    题意:求字符串中的最短循环节,并输出该循环节

    KMP最小循环节、循环周期:
    定理:假设S的长度为len,则S存在最小循环节,循环节的长度L为len-next[len],子串为S[0…len-next[len]-1]。
    (1)如果len可以被len - next[len]整除,则表明字符串S可以完全由循环节循环组成,循环周期T=len/L。
    (2)如果不能,说明还需要再添加几个字母才能补全。需要补的个数是循环个数L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]。

    注意这里的len是原字符串的len+1;

     1 #include<cstdio>
     2 #include<string.h>
     3 #include<algorithm>
     4 using namespace std;
     5 int T, len;
     6 char s[100000 + 5];
     7 int nex[100000 + 5];
     8 
     9 void get_next(char* p, int next[]){
    10     int pLen = strlen(p) + 1;//要求循环节长度时这里才+1
    11     next[0] = -1;
    12     int k = -1;
    13     int j = 0;
    14     while (j < pLen - 1){  
    15         if (k == -1 || p[j] == p[k]){
    16             ++j;++k;
    17             if (p[j] != p[k])
    18                 next[j] = k;
    19             else
    20                 next[j] = next[k];
    21         }
    22         else{
    23             k = next[k];
    24         }
    25     }
    26 }
    27 
    28 int kmp(char* s, char* p){
    29     int i = 0;
    30     int j = 0;
    31     int sLen = strlen(s);
    32     int pLen = strlen(p);
    33     while (i < sLen && j < pLen){
    34             //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++      
    35         if (j == -1 || s[i] == p[j]){
    36             i++;
    37             j++;
    38         }
    39         else{
    40             //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]      
    41             //next[j]即为j所对应的next值        
    42             j = nex[j];
    43         }
    44     }
    45     if (j == pLen)
    46         return i - j;
    47     else
    48         return -1;
    49 }
    50 
    51 int main() {
    52     scanf("%d", &T);
    53     while (T--) {
    54         memset(nex, 0, sizeof(nex));
    55         scanf("%d", &len);
    56         scanf("%s", s);
    57         len = strlen(s);
    58         get_next(s, nex);
    59         printf("%d
    ", len - nex[len]);
    60         for (int i = 0; i < len - nex[len]; i++)
    61             printf("%c", s[i]);
    62         printf("
    ");
    63     }
    64     return 0;
    65 }

    HDU1711(数字KMP)

     1 #include<cstdio>
     2 #include<string.h>
     3 #include<algorithm>
     4 using namespace std;
     5 int T, len;
     6 int len1, len2;
     7 int s1[1000000 + 5];
     8 int s2[1000000 + 5];
     9 int nex[1000000 + 5];
    10 
    11 void get_next(int* p, int next[]) {
    12     int pLen = len2;//要求循环节长度时这里才+1
    13     next[0] = -1;
    14     int k = -1;
    15     int j = 0;
    16     while (j < pLen - 1) {
    17         if (k == -1 || p[j] == p[k]) {
    18             ++j; ++k;
    19             if (p[j] != p[k])
    20                 next[j] = k;
    21             else
    22                 next[j] = next[k];
    23         }
    24         else {
    25             k = next[k];
    26         }
    27     }
    28 }
    29 
    30 int kmp(int* s, int* p) {
    31     int i = 0;
    32     int j = 0;
    33     int sLen = len1;
    34     int pLen = len2;
    35     get_next(s2, nex);
    36     while (i < sLen && j < pLen) {
    37         //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++      
    38         if (j == -1 || s[i] == p[j]) {
    39             i++;
    40             j++;
    41         }
    42         else {
    43             //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]      
    44             //next[j]即为j所对应的next值        
    45             j = nex[j];
    46         }
    47     }
    48     if (j == pLen)
    49         return i - j;
    50     else
    51         return -1;
    52 }
    53 
    54 int main() {
    55     scanf("%d", &T);
    56     while (T--) {
    57         scanf("%d %d", &len1, &len2);
    58         for (int i = 0; i < len1; i++)
    59             scanf("%d", &s1[i]);
    60         for (int i = 0; i < len2; i++)
    61             scanf("%d", &s2[i]);
    62         if (kmp(s1,s2) == -1)
    63             printf("-1
    ");
    64         else
    65             printf("%d
    ", kmp(s1,s2)+1);
    66     }
    67     return 0;
    68 }
  • 相关阅读:
    Navicat Premium_11.2.7简体中文版 破解版本 windows版本 失效
    php多维数组排序 3
    php 多维数组排序
    php对二维数组排序
    mysql子查询批量找id最大的
    教你如何选择相机的曝光模式(转)
    3分钟搞懂曝光直方图(转)
    摄影新手最想知道的10件事(转)
    教你搞懂光圈大小的成像差异(转)
    新手必须掌握的20个摄影构图法 转
  • 原文地址:https://www.cnblogs.com/romaLzhih/p/9489822.html
Copyright © 2011-2022 走看看