zoukankan      html  css  js  c++  java
  • KMP全家桶练习

    A:

    题意:给出一个主序列,和一个匹配序列,如果能够匹配,则输出匹配序列第一个数在主序列中的位置.

    思路:KMP的模版题不多说

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <stdbool.h>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <string.h>
     8 #include <math.h>
     9 #include <vector>
    10 #include <queue>
    11 #include <stack>
    12 #include <set>
    13 #include <map>
    14 
    15 #define INF 0x3f3f3f3f
    16 #define LL long long
    17 #define MAXN 1000010
    18 using namespace std;
    19 
    20 int len1,len2;
    21 int P[MAXN],S[MAXN];
    22 
    23 void GetNext(int P[], int next[])
    24 {
    25     int p_len = len1;
    26     int i = 0;
    27     int j = -1;
    28     next[0] = -1;
    29 
    30     while (i < p_len)
    31     {
    32         if (j == -1 || P[i] == P[j])
    33         {
    34             i++;
    35             j++;
    36             next[i] = j;
    37         }
    38         else
    39             j = next[j];
    40     }
    41 }
    42 
    43 
    44 int KMP(int S[],int P[], int next[])
    45 {
    46     GetNext(P, next);
    47 
    48     int i = 0;
    49     int j = 0;
    50     int s_len = len2;
    51     int p_len = len1;
    52 
    53     while (i < s_len && j < p_len)
    54     {
    55         if (j == -1 || S[i] == P[j])
    56         {
    57             i++;
    58             j++;
    59         }
    60         else
    61             j = next[j];
    62     }
    63 
    64     if (j == p_len)
    65         return i - j + 1;
    66 
    67     return -1;
    68 }
    69 
    70 int main()
    71 {
    72     ios_base::sync_with_stdio(0);
    73     cin.tie(NULL);
    74     int n;
    75     cin >> n;
    76     while (n--)
    77     {
    78         int next[1000010] = { 0 };
    79         cin >> len2 >> len1;
    80         for (int i=0;i<len2;i++)
    81             cin >> S[i];
    82         for (int i=0;i<len1;i++)
    83             cin >> P[i];
    84         GetNext(P,next);
    85         cout << KMP(S,P,next) << endl;
    86     }
    87 
    88     return 0;
    89 }
    Ackerman

    B:

    题意:计算模式串在匹配串中出现的次数

    思路:直接将KMP算法稍稍改动一点就好了

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <stdbool.h>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <string.h>
     8 #include <math.h>
     9 #include <vector>
    10 #include <queue>
    11 #include <stack>
    12 #include <set>
    13 #include <map>
    14 
    15 #define INF 0x3f3f3f3f
    16 #define LL long long
    17 #define MAXN 1000010
    18 using namespace std;
    19 
    20 int len1,len2;
    21 char P[MAXN],S[MAXN];
    22 int cnt = 0;
    23 
    24 void GetNext(char P[], int next[])
    25 {
    26     int p_len = len1;
    27     int i = 0;
    28     int j = -1;
    29     next[0] = -1;
    30 
    31     while (i < p_len)
    32     {
    33         if (j == -1 || P[i] == P[j])
    34         {
    35             i++;
    36             j++;
    37             next[i] = j;
    38         }
    39         else
    40             j = next[j];
    41     }
    42 }
    43 
    44 
    45 int KMP(char S[],char P[], int next[])
    46 {
    47     GetNext(P, next);
    48 
    49     int i = 0;
    50     int j = 0;
    51     int s_len = len2;
    52     int p_len = len1;
    53 
    54     while (i < s_len)
    55     {
    56         if (j == -1 || S[i] == P[j])
    57         {
    58             i++;
    59             j++;
    60         }
    61         else
    62             j = next[j];
    63         if (j == p_len)
    64             cnt++;
    65     }
    66 
    67 
    68     return cnt;
    69 }
    70 
    71 int main()
    72 {
    73     ios_base::sync_with_stdio(0);
    74     cin.tie(NULL);
    75     int n;
    76     cin >> n;
    77     while (n--)
    78     {
    79         int next[MAXN] = {0};
    80         cin >> P;
    81         cin >> S;
    82         cnt = 0;
    83         len2 = strlen(S);
    84         len1 = strlen(P);
    85         GetNext(P,next);
    86         cout << KMP(S,P,next) << endl;
    87     }
    88     return 0;
    89 }
    Ackerman

    C:

    题意:与B一样也是计算模式串在匹配串中出现的次数

    思路:代码大致和B一样。但是需要注意的是B题可以重复匹配:比如AZAZA  我们可是匹配的是AZA或者AZA

    但是在C题是不可以这个样子的,所以我们稍微改动一下也可以AC

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <stdbool.h>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <string.h>
     8 #include <math.h>
     9 #include <vector>
    10 #include <queue>
    11 #include <stack>
    12 #include <set>
    13 #include <map>
    14 
    15 #define INF 0x3f3f3f3f
    16 #define LL long long
    17 #define MAXN 1000010
    18 using namespace std;
    19 
    20 int len1,len2;
    21 char P[MAXN],S[MAXN];
    22 int cnt = 0;
    23 
    24 void GetNext(char P[], int next[])
    25 {
    26     int p_len = len1;
    27     int i = 0;
    28     int j = -1;
    29     next[0] = -1;
    30 
    31     while (i < p_len)
    32     {
    33         if (j == -1 || P[i] == P[j])
    34         {
    35             i++;
    36             j++;
    37             next[i] = j;
    38         }
    39         else
    40             j = next[j];
    41     }
    42 }
    43 
    44 
    45 int KMP(char S[],char P[], int next[])
    46 {
    47     GetNext(P, next);
    48 
    49     int i = 0;
    50     int j = 0;
    51     int s_len = len2;
    52     int p_len = len1;
    53 
    54     while (i < s_len)
    55     {
    56         if (j == -1 || S[i] == P[j])
    57         {
    58             i++;
    59             j++;
    60         }
    61         else
    62             j = next[j];
    63         if (j == p_len) {
    64             cnt++;
    65             j=0;
    66         }
    67     }
    68 
    69 
    70     return cnt;
    71 }
    72 
    73 int main()
    74 {
    75     ios_base::sync_with_stdio(0);
    76     cin.tie(NULL);
    77     while (cin >> S)
    78     {
    79         if (strcmp(S,"#") == 0)
    80             break;
    81         cin >> P;
    82         int next[MAXN] = {0};
    83         len1 = strlen(P);
    84         len2 = strlen(S);
    85         GetNext(P,next);
    86         cnt = 0;
    87         cout << KMP(S,P,next) << endl;
    88     }
    89     return 0;
    90 }
    Ackerman

    D:

    题意:给一串字符串,问至少添加多少个字符,使得这个字符串有至少两个循环节

    思路:其实就是对kmp算法的next数组的理解;

    next数组的一些应用:

    1、判断是否是周期字符串:  n%(n-next[n]) == 0

    2、求循环节的长度: n-next[n]

    3、求循环节的个数:n/(n-next[n])

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <stdbool.h>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <string.h>
     8 #include <math.h>
     9 #include <vector>
    10 #include <queue>
    11 #include <stack>
    12 #include <set>
    13 #include <map>
    14 
    15 #define INF 0x3f3f3f3f
    16 #define LL long long
    17 #define MAXN 1000010
    18 using namespace std;
    19 
    20 int len1,len2;
    21 char P[MAXN],S[MAXN];
    22 int cnt = 0;
    23 
    24 void GetNext(char P[], int next[])
    25 {
    26     int p_len = len1;
    27     int i = 0;
    28     int j = -1;
    29     next[0] = -1;
    30 
    31     while (i < p_len)
    32     {
    33         if (j == -1 || P[i] == P[j])
    34         {
    35             i++;
    36             j++;
    37             next[i] = j;
    38         }
    39         else
    40             j = next[j];
    41     }
    42 }
    43 
    44 
    45 int KMP(char S[],char P[], int next[])
    46 {
    47     GetNext(P, next);
    48 
    49     int i = 0;
    50     int j = 0;
    51     int s_len = len2;
    52     int p_len = len1;
    53 
    54     while (i < s_len)
    55     {
    56         if (j == -1 || S[i] == P[j])
    57         {
    58             i++;
    59             j++;
    60         }
    61         else
    62             j = next[j];
    63         if (j == p_len) {
    64             cnt++;
    65             j=0;
    66         }
    67     }
    68 
    69 
    70     return cnt;
    71 }
    72 
    73 int main()
    74 {
    75     ios_base::sync_with_stdio(0);
    76     cin.tie(NULL);
    77     int n;
    78     cin >> n;
    79     while (n--)
    80     {
    81         cin >> P;
    82         int next[MAXN] = {0};
    83         len1 = strlen(P);
    84         GetNext(P,next);
    85         int cir = len1-next[len1]; //循环节的长度
    86         if (next[len1] == 0)         {
    87             printf("%d
    ",len1);
    88             continue;
    89         }
    90         if (len1%cir == 0)// 判断是否是周期字符串
    91         {
    92             printf("0
    ");
    93             continue;
    94         }
    95         int count = len1/cir;
    96         printf("%d
    ",(count+1)*cir-len1);
    97     }
    98     return 0;
    99 }
    Ackerman

    E:

    题意:求出所有前缀(满足是两个或两个以上的循环节组成的字符串)

    思路:只要知道next数组的应用,这题直接水过

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <stdbool.h>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <string.h>
     8 #include <math.h>
     9 #include <vector>
    10 #include <queue>
    11 #include <stack>
    12 #include <set>
    13 #include <map>
    14 
    15 #define INF 0x3f3f3f3f
    16 #define LL long long
    17 #define MAXN 1000010
    18 using namespace std;
    19 
    20 int len1,len2;
    21 char P[MAXN],S[MAXN];
    22 int cnt = 0;
    23 
    24 void GetNext(char P[], int next[])
    25 {
    26     int p_len = len1;
    27     int i = 0;
    28     int j = -1;
    29     next[0] = -1;
    30 
    31     while (i < p_len)
    32     {
    33         if (j == -1 || P[i] == P[j])
    34         {
    35             i++;
    36             j++;
    37             next[i] = j;
    38         }
    39         else
    40             j = next[j];
    41     }
    42 }
    43 
    44 
    45 int KMP(char S[],char P[], int next[])
    46 {
    47     GetNext(P, next);
    48 
    49     int i = 0;
    50     int j = 0;
    51     int s_len = len2;
    52     int p_len = len1;
    53 
    54     while (i < s_len)
    55     {
    56         if (j == -1 || S[i] == P[j])
    57         {
    58             i++;
    59             j++;
    60         }
    61         else
    62             j = next[j];
    63         if (j == p_len) {
    64             cnt++;
    65             j=0;
    66         }
    67     }
    68 
    69 
    70     return cnt;
    71 }
    72 
    73 int main()
    74 {
    75     ios_base::sync_with_stdio(0);
    76     cin.tie(NULL);
    77     int n;
    78     int t = 1;
    79     while (cin >> n)
    80     {
    81         if (n == 0)
    82             break;
    83         printf("Test case #%d
    ",t++);
    84         cin >> P;
    85         int next[MAXN] = {0};
    86         len1 = n;
    87         GetNext(P,next);
    88         for (int i=1;i<=len1;i++) {
    89             if(i%(i-next[i])==0 && (i/(i-next[i]))>1)
    90                 printf("%d %d
    ",i,i/(i-next[i]));
    91         }
    92         printf("
    ");
    93     }
    94     return 0;
    95 }
    Ackerman

    F:

    题意: 求字符串的周期

    水~

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <stdbool.h>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <string.h>
     8 #include <math.h>
     9 #include <vector>
    10 #include <queue>
    11 #include <stack>
    12 #include <set>
    13 #include <map>
    14 
    15 #define INF 0x3f3f3f3f
    16 #define LL long long
    17 #define MAXN 1000020
    18 using namespace std;
    19 
    20 int len1,len2;
    21 char P[MAXN],S[MAXN];
    22 int cnt = 0;
    23 int nexts[MAXN];
    24 
    25 void GetNext(char P[], int next[])
    26 {
    27     int p_len = len1;
    28     int i = 0;
    29     int j = -1;
    30     next[0] = -1;
    31 
    32     while (i < p_len)
    33     {
    34         if (j == -1 || P[i] == P[j])
    35         {
    36             i++;
    37             j++;
    38             next[i] = j;
    39         }
    40         else
    41             j = next[j];
    42     }
    43 }
    44 
    45 
    46 int KMP(char S[],char P[], int next[])
    47 {
    48     GetNext(P, next);
    49 
    50     int i = 0;
    51     int j = 0;
    52     int s_len = len2;
    53     int p_len = len1;
    54 
    55     while (i < s_len)
    56     {
    57         if (j == -1 || S[i] == P[j])
    58         {
    59             i++;
    60             j++;
    61         }
    62         else
    63             j = next[j];
    64         if (j == p_len) {
    65             cnt++;
    66             j=0;
    67         }
    68     }
    69 
    70 
    71     return cnt;
    72 }
    73 
    74 int main()
    75 {
    76     while (~scanf("%s",P))
    77     {
    78         getchar();
    79         if (strcmp(P,".") == 0)
    80             break;
    81         len1 = strlen(P);
    82         GetNext(P,nexts);
    83         if (len1%(len1-nexts[len1])==0)
    84             printf("%d
    ",len1/(len1-nexts[len1]));
    85         else
    86             printf("1
    ");
    87     }
    88     return 0;
    89 }
    Ackerman

    G:

    题意:给出一个字符串str,求出str中存在多少子串,使得这些子串既是str的前缀,又是str的后缀。从小到大依次输出这些子串的长度。

    思路:这题挺有意思的。

    next数组表示的是i前面的几个的和最前面的几个相等。那么我们不妨就从最后开始,那不就是后缀和前缀了吗?然后next不断往前移动直到0或者-1停止

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <stdbool.h>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <string.h>
     8 #include <math.h>
     9 #include <vector>
    10 #include <queue>
    11 #include <stack>
    12 #include <set>
    13 #include <map>
    14 
    15 #define INF 0x3f3f3f3f
    16 #define LL long long
    17 #define MAXN 1000020
    18 using namespace std;
    19 
    20 int len1,len2;
    21 char P[MAXN],S[MAXN];
    22 int cnt = 0;
    23 int nexts[MAXN];
    24 int ans[MAXN];
    25 
    26 void GetNext(char P[], int next[])
    27 {
    28     int p_len = len1;
    29     int i = 0;
    30     int j = -1;
    31     next[0] = -1;
    32 
    33     while (i < p_len)
    34     {
    35         if (j == -1 || P[i] == P[j])
    36         {
    37             i++;
    38             j++;
    39             next[i] = j;
    40         }
    41         else
    42             j = next[j];
    43     }
    44 }
    45 
    46 
    47 int KMP(char S[],char P[], int next[])
    48 {
    49     GetNext(P, next);
    50 
    51     int i = 0;
    52     int j = 0;
    53     int s_len = len2;
    54     int p_len = len1;
    55 
    56     while (i < s_len)
    57     {
    58         if (j == -1 || S[i] == P[j])
    59         {
    60             i++;
    61             j++;
    62         }
    63         else
    64             j = next[j];
    65         if (j == p_len) {
    66             cnt++;
    67             j=0;
    68         }
    69     }
    70 
    71 
    72     return cnt;
    73 }
    74 
    75 int main()
    76 {
    77     while (~scanf("%s",P))
    78     {
    79         getchar();
    80         len1 = strlen(P);
    81         int len = len1;
    82         GetNext(P,nexts);
    83         int cnt=0;
    84         while (nexts[len1])
    85         {
    86             ans[cnt++] = nexts[len1];
    87             len1 = nexts[len1];
    88         }
    89         sort(ans,ans+cnt);
    90         for (int i=0;i<cnt;i++)
    91             printf("%d ",ans[i]);
    92         printf("%d
    ",len);
    93     }
    94     return 0;
    95 }
    Ackerman

    I:

    题意:找前一个字符串的前缀和后一个字符串的后缀一样的最长长度

    思路:把这两个字符串连起来,然后你就会发现这题其实和G题有点像。也就是看后面和最前面相等的个数最多罢了。只不过要注意虽然连起来了,但是它其实还是两个不一样的,所以如果这个相等长度比它们其中任何一个长度要大的话其实是不可以的,那就再继续找小一点的呗

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <iostream>
      4 #include <stdbool.h>
      5 #include <stdlib.h>
      6 #include <string>
      7 #include <string.h>
      8 #include <math.h>
      9 #include <vector>
     10 #include <queue>
     11 #include <stack>
     12 #include <set>
     13 #include <map>
     14 
     15 #define INF 0x3f3f3f3f
     16 #define LL long long
     17 #define MAXN 1000020
     18 using namespace std;
     19 
     20 int len1,len2;
     21 char P[MAXN],S[MAXN];
     22 char str[MAXN];
     23 int cnt = 0;
     24 int nexts[MAXN];
     25 
     26 
     27 void GetNext(char P[], int next[])
     28 {
     29     int p_len = len1;
     30     int i = 0;
     31     int j = -1;
     32     next[0] = -1;
     33 
     34     while (i < p_len)
     35     {
     36         if (j == -1 || P[i] == P[j])
     37         {
     38             i++;
     39             j++;
     40             next[i] = j;
     41         }
     42         else
     43             j = next[j];
     44     }
     45 }
     46 
     47 
     48 int KMP(char S[],char P[], int next[])
     49 {
     50     GetNext(P, next);
     51 
     52     int i = 0;
     53     int j = 0;
     54     int s_len = len2;
     55     int p_len = len1;
     56 
     57     while (i < s_len)
     58     {
     59         if (j == -1 || S[i] == P[j])
     60         {
     61             i++;
     62             j++;
     63         }
     64         else
     65             j = next[j];
     66         if (j == p_len) {
     67             cnt++;
     68             j=0;
     69         }
     70     }
     71 
     72 
     73     return cnt;
     74 }
     75 
     76 int main()
     77 {
     78     while (~scanf("%s%s", P,S))
     79     {
     80         len2 = strlen(S);
     81         int len = strlen(P);
     82         strcat(P, S);
     83         len1 = strlen(P);
     84         GetNext(P,nexts);
     85         int ans = nexts[len1];
     86         while (ans > len || ans > len2)
     87         {
     88             ans = nexts[ans];
     89         }
     90         if (ans == 0 || ans == -1)
     91         {
     92             printf("0
    ");
     93         }
     94         else
     95         {
     96             P[ans] = '';
     97             printf("%s %d
    ",P,ans);
     98         }
     99     }
    100 
    101     return 0;
    102 }
    Ackerman

    J:

    题意:给一串字符串,问这串字符串所有的前缀总共在这个字符串中出现了几次。 

    思路:其实这道题也是next数组的运用。前面已经说了next数组表示的是i之前的几个和字符串最前面的几个相等。将字符串所有的前缀0-i在i+1-n出现的次数相加得到 sum, sum再加上n就是了

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <stdbool.h>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <string.h>
     8 #include <math.h>
     9 #include <vector>
    10 #include <queue>
    11 #include <stack>
    12 #include <set>
    13 #include <map>
    14 
    15 #define INF 0x3f3f3f3f
    16 #define LL long long
    17 #define MAXN 1000020
    18 using namespace std;
    19 
    20 int len1,len2;
    21 char P[MAXN],S[MAXN];
    22 int cnt = 0;
    23 int nexts[MAXN];
    24 int ans[MAXN];
    25 
    26 
    27 void GetNext(char P[], int next[])
    28 {
    29     int p_len = len1;
    30     int i = 0;
    31     int j = -1;
    32     next[0] = -1;
    33 
    34     while (i < p_len)
    35     {
    36         if (j == -1 || P[i] == P[j])
    37         {
    38             i++;
    39             j++;
    40             next[i] = j;
    41         }
    42         else
    43             j = next[j];
    44     }
    45 }
    46 
    47 
    48 int KMP(char S[],char P[], int next[])
    49 {
    50     GetNext(P, next);
    51 
    52     int i = 0;
    53     int j = 0;
    54     int s_len = len2;
    55     int p_len = len1;
    56 
    57     while (i < s_len)
    58     {
    59         if (j == -1 || S[i] == P[j])
    60         {
    61             i++;
    62             j++;
    63         }
    64         else
    65             j = next[j];
    66         if (j == p_len) {
    67             cnt++;
    68             j=0;
    69         }
    70     }
    71 
    72 
    73     return cnt;
    74 }
    75 
    76 int main()
    77 {
    78     int T;
    79     scanf("%d",&T);
    80     while (T--)
    81     {
    82         memset(ans,0, sizeof(ans));
    83         int n;
    84         scanf("%d",&n);
    85         scanf("%s",&P);
    86         getchar();
    87         len1 = strlen(P);
    88         GetNext(P,nexts);
    89         int sum = 0;
    90         for (int i=1;i<=len1;i++)
    91         {
    92             ans[i] = ans[nexts[i]]+1;
    93             sum += ans[i];
    94         }
    95         printf("%d
    ",sum%10007);
    96     }
    97     return 0;
    98 }
    Ackerman

    O:

    题意:给出一段文本,求出里面"Doge"的个数,大小写不敏感.

    思路:把文本合并成一段,然后之间KMP就好了

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <stdbool.h>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <string.h>
     8 #include <math.h>
     9 #include <vector>
    10 #include <queue>
    11 #include <stack>
    12 #include <set>
    13 #include <map>
    14 
    15 #define INF 0x3f3f3f3f
    16 #define LL long long
    17 #define MAXN 200005
    18 using namespace std;
    19 
    20 char P[MAXN];
    21 char str[MAXN];
    22 char S[MAXN];
    23 int nexts[MAXN];
    24 int cnt = 0;
    25 int len1,len2;
    26 
    27 void GetNext(char P[], int next[])
    28 {
    29     int p_len = len1;
    30     int i = 0;
    31     int j = -1;
    32     next[0] = -1;
    33 
    34     while (i < p_len)
    35     {
    36         if (j == -1 || P[i] == P[j])
    37         {
    38             i++;
    39             j++;
    40             next[i] = j;
    41         }
    42         else
    43             j = next[j];
    44     }
    45 }
    46 
    47 
    48 void KMP(char S[], char P[], int next[])
    49 {
    50     int i = 0;
    51     int j = 0;
    52     int s_len = len2;
    53     int p_len = len1;
    54 
    55     while (i < s_len)
    56     {
    57         if (j == -1 || S[i] == P[j])
    58         {
    59             i++;
    60             j++;
    61         }
    62         else
    63             j = next[j];
    64         if (j == p_len){
    65             cnt++;
    66         }
    67     }
    68 }
    69 
    70 int main()
    71 {
    72     //freopen("../in.txt","r",stdin);
    73     ios_base::sync_with_stdio(0);
    74     cin.tie(NULL);
    75     cin >> S;
    76     cnt = 0;
    77     while (cin >> str)
    78     {
    79         strcat(S,str);
    80     }
    81     len2 = strlen(S);
    82     for (int i=0;i<len2;i++)
    83     {
    84         if (S[i]>='A' && S[i]<='Z')
    85         {
    86             S[i]+=32;
    87         }
    88     }
    89     P[0]='d';
    90     P[1]='o';
    91     P[2]='g';
    92     P[3]='e';
    93     P[4]='';
    94     len1 = strlen(P);
    95     GetNext(P,nexts);
    96     KMP(S,P,nexts);
    97     cout << cnt << endl;
    98     return 0;
    99 }
    Ackerman

    P:

    题目意思是一个字符串中前缀后缀相等且能在中间找到,重要的一个点是三者不能重叠 EAEBE 满足这种形式

    思路:先用KMP将其分为两段,然后取去掉首位,看中间的那一段是否符合就好了

      1 #include <stdio.h>
      2 #include <algorithm>
      3 #include <iostream>
      4 #include <stdbool.h>
      5 #include <stdlib.h>
      6 #include <string>
      7 #include <string.h>
      8 #include <math.h>
      9 #include <vector>
     10 #include <queue>
     11 #include <stack>
     12 #include <set>
     13 #include <map>
     14 
     15 #define INF 0x3f3f3f3f
     16 #define LL long long
     17 #define MAXN 1000020
     18 using namespace std;
     19 
     20 int len1,len2;
     21 char P[MAXN],S[MAXN];
     22 int cnt = 0;
     23 int nexts[MAXN];
     24 char str[MAXN];
     25 
     26 
     27 void GetNext(char P[], int next[])
     28 {
     29     int p_len = len1;
     30     int i = 0;
     31     int j = -1;
     32     next[0] = -1;
     33 
     34     while (i < p_len)
     35     {
     36         if (j == -1 || P[i] == P[j])
     37         {
     38             i++;
     39             j++;
     40             next[i] = j;
     41         }
     42         else
     43             j = next[j];
     44     }
     45 }
     46 
     47 
     48 int KMP(char S[],char P[], int next[])
     49 {
     50     GetNext(P, next);
     51 
     52     int i = 0;
     53     int j = 0;
     54     int s_len = len2;
     55     int p_len = len1;
     56 
     57     while (i < s_len)
     58     {
     59         if (j == -1 || S[i] == P[j])
     60         {
     61             i++;
     62             j++;
     63         }
     64         else
     65             j = next[j];
     66         if (j == p_len) {
     67             cnt++;
     68             j=0;
     69         }
     70     }
     71 
     72 
     73     return cnt;
     74 }
     75 
     76 void solve()
     77 {
     78     len1 = strlen(P);
     79     GetNext(P,nexts);
     80     int len = len1;
     81     int max_d = nexts[len1];
     82     while (2*max_d>len)
     83     {
     84         len1 = nexts[len1];
     85         max_d = nexts[len1];
     86     }
     87     int ans = 0;
     88     int flag = 1;
     89     while (max_d)
     90     {
     91         strncpy(S,P+max_d,len-2*max_d);
     92         strncpy(str,P,max_d);
     93         str[max_d] = '';
     94         if (S!=NULL)
     95         {
     96             flag = 0;
     97             if (ans<max_d)
     98                 ans = max_d;
     99         }
    100         len1 = nexts[len1];
    101         max_d = nexts[len1];
    102     }
    103     if (flag)
    104         printf("0
    ");
    105     else
    106         printf("%d
    ",ans);
    107 }
    108 
    109 
    110 
    111 int main()
    112 {
    113     int T;
    114     scanf("%d",&T);
    115     while (T--)
    116     {
    117         scanf("%s",P);
    118         solve();
    119     }
    120     return 0;
    121 }
    Ackerman

    训练总结:

    其实感觉KMP的运用的灵活很大一部取决于next数组的运用:

    next数组的一些应用:

    1、判断是否是周期字符串:  n%(n-next[n]) == 0

    2、求循环节的长度: n-next[n]

    3、求循环节的个数:n/(n-next[n])

  • 相关阅读:
    安卓linux真机调试
    Java开发必装的IntelliJ IDEA插件
    在switch中的case语句中声明变量会被提前
    PostgresSQL 数组包含@>
    SQL 增加列、修改列、删除列
    ConcurrentHashMap 的实现原理
    Apache——DBUtils框架ResultSetHandler接口使用
    [转](不理想)Ubuntu下更改主显示器
    [问题记录]Java关于可变参数重载问题的测试
    使用openssl生成双向加密证书(转)
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/11285838.html
Copyright © 2011-2022 走看看