• KMP算法


    为了解决字符串匹配问题

    给你两个字符串,寻找其中一个字符串是否包含另一个字符串,如果包含,返回包含的起始位置。

     1 //str为子串
     2 //prt为母串
     3 
     4 
     5 void cal_next(char *str, int *next, int len)
     6 {
     7     next[0] = -1;//next[0]初始化为-1,-1表示不存在相同的最大前缀和最大后缀
     8     int k = -1;//k初始化为-1
     9     for (int q = 1; q <= len-1; q++)
    10     {
    11         while (k > -1 && str[k + 1] != str[q])//如果下一个不同,那么k就变成next[k],注意next[k]是小于k的,无论k取任何值。
    12         {
    13             k = next[k];//往前回溯
    14         }
    15         if (str[k + 1] == str[q])//如果相同,k++
    16         {
    17             k = k + 1;
    18         }
    19         next[q] = k;//这个是把算的k的值(就是相同的最大前缀和最大后缀长)赋给next[q]
    20     }
    21 }
    22 
    23 int KMP(char *str, int slen, char *ptr, int plen)
    24 {
    25     int *next = new int[plen];
    26     cal_next(ptr, next, plen);//计算next数组
    27     int k = -1;
    28     for (int i = 0; i < slen; i++)
    29     {
    30         while (k >-1&& ptr[k + 1] != str[i])//ptr和str不匹配,且k>-1(表示ptr和str有部分匹配)
    31             k = next[k];//往前回溯
    32         if (ptr[k + 1] == str[i])
    33             k = k + 1;
    34         if (k == plen-1)//说明k移动到ptr的最末端
    35         {
    36             //cout << "在位置" << i-plen+1<< endl;
    37             //k = -1;//重新初始化,寻找下一个
    38             //i = i - plen + 1;//i定位到该位置,外层for循环i++可以继续找下一个(这里默认存在两个匹配字符串可以部分重叠),感谢评论中同学指出错误。
    39             return i-plen+1;//返回相应的位置
    40         }
    41     }
    42     return -1;  
    43 }

    模板:

     1 #include<stdio.h>
     2 #include<string.h>
     3 void makeNext(const char P[],int next[])
     4 {
     5     int q,k;
     6     int m = strlen(P);
     7     next[0] = 0;
     8     for (q = 1,k = 0; q < m; ++q)
     9     {
    10         while(k > 0 && P[q] != P[k])
    11             k = next[k-1];
    12         if (P[q] == P[k])
    13         {
    14             k++;
    15         }
    16         next[q] = k;
    17     }
    18 }
    19 
    20 int kmp(const char T[],const char P[],int next[])
    21 {
    22     int n,m;
    23     int i,q;
    24     n = strlen(T);
    25     m = strlen(P);
    26     makeNext(P,next);
    27     for (i = 0,q = 0; i < n; ++i)
    28     {
    29         while(q > 0 && P[q] != T[i])
    30             q = next[q-1];
    31         if (P[q] == T[i])
    32         {
    33             q++;
    34         }
    35         if (q == m)
    36         {
    37             printf("Pattern occurs with shift:%d
    ",(i-m+1));
    38         }
    39     }    
    40 }
    41 
    42 int main()
    43 {
    44     int i;
    45     int next[20]={0};
    46     char T[] = "ababxbababcadfdsss";
    47     char P[] = "abcdabd";
    48     printf("%s
    ",T);
    49     printf("%s
    ",P );
    50     // makeNext(P,next);
    51     kmp(T,P,next);
    52     for (i = 0; i < strlen(P); ++i)
    53     {
    54         printf("%d ",next[i]);
    55     }
    56     printf("
    ");
    57 
    58     return 0;
    59 }

     KMP求子串出现的次数

     1 #include<cstdio>
     2 #include<cstring>
     3 using namespace std;
     4 
     5 const int MAXW=10001,MAXT=1000001;
     6 char W[MAXW],T[MAXT];
     7 int next[MAXW];
     8 int lenW,lenT;
     9 
    10 void getnext(int lenW)
    11 {
    12     int i=0,j=-1;
    13     next[i]=-1;
    14     while(i<lenW) {
    15         if(j==-1||W[i]==W[j]) {
    16             next[++i]=++j;
    17         }
    18         else j=next[j];
    19     }
    20 }
    21 
    22 int kmp(int pos,int lenW,int lenT)
    23 {
    24     int i=pos,j=0,ans=0;
    25     while(i<lenT) {
    26         if(T[i]==W[j]||j==-1) ++i,++j;
    27         else j=next[j];
    28         if(j==lenW) {
    29             ans++;
    30             j=next[j-1];
    31             i--;
    32         }
    33     }
    34     return ans;
    35 }
    36 
    37 
    38 int main()
    39 {
    40     int n;
    41     scanf("%d",&n);
    42     while(n--) {
    43         scanf("%s%s",W,T);
    44         lenW=strlen(W);
    45         lenT=strlen(T);
    46         getnext(lenW);
    47         printf("%d
    ",kmp(0,lenW,lenT));
    48     }
    49     return 0;
    50 }
  • 相关阅读:
    使用canvas技术在网页上绘制鲜花
    java连接Access数据库
    L2-009. 抢红包
    L2-008. 最长对称子串
    L1-032. Left-pad
    L1-016. 查验身份证
    L1-005. 考试座位号
    L1-030. 一帮一
    L1-023. 输出GPLT
    L1-028. 判断素数
  • 原文地址:https://www.cnblogs.com/ouyang_wsgwz/p/8886293.html
Copyright © 2020-2023  润新知