热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

KMP算法应用举例

KMP是字符串匹配的经典算法也是众多字符串基础的重中之重A.题意:给T组数据,每组有长度为n和m的母串和模式串。判断模式串是否是母串的子串,如果是输出最先匹配完成的位置,否则输出-

KMP是字符串匹配的经典算法

也是众多字符串基础的重中之重

A.

题意:给T组数据,每组有长度为n和m的母串和模式串。判断模式串是否是母串的子串,如果是输出最先匹配完成的位置,否则输出-1.

做法:直接套用模板。把char改成int。kmp函数中在模式串遍历到结尾的时候return,若没遍历到结尾,也就是不是子串返回-1

 1 [cpp] view plain copy
 2 #include   
 3 #include    
 4 #include   
 5 using namespace std;  
 6 int nexta[10005],a[1000005],s[10005];  
 7 int n,m;  
 8 void getnexta(int s[])  
 9 {  
10     memset(nexta,0,sizeof(nexta));  
11     int k = -1,j = 0;  
12     nexta[0] = -1;  
13   
14     while(j < n )  
15     {  
16   
17         if(k == -1 || s[k] == s[j])  
18         {  
19             nexta[j + 1] = k + 1;  
20             j ++;  
21             k ++;  
22         }  
23         else  
24         {  
25             k = nexta[k];  
26         }  
27     }  
28   
29 }  
30 int kmp(int s[],int t[])//t模式串,s母串  
31 {  
32     getnexta(t);  
33   
34     int i = 0,j = 0;  
35     while(i  m)  
36     {  
37         if(j == -1 || s[i] == t[j])  
38         {  
39             i ++;  
40             j ++;  
41         }  
42         else  
43         {  
44             j = nexta[j];  
45         }  
46         if(j == m)  
47         {  
48             return i - j+ 1;  
49         }  
50     }  
51     return -1;  
52 }  
53 int main()  
54 {  
55    // freopen("in.txt","r",stdin);  
56     int T;  
57     scanf("%d",&T);  
58     while(T--)  
59     {  
60         scanf("%d%d",&n,&m);  
61         for(int i = 0;i )  
62         {  
63             scanf("%d",&a[i]);  
64         }  
65         for(int j = 0; j )  
66         {  
67             scanf("%d",&s[j]);  
68         }  
69         printf("%d\n",kmp(a,s));  
70     }  
71     return 0;  
72 } 

B.

题意:给T组数据,每组有两个字符串按顺序分别为模式串和母串。判断模式串在母串中出现的次数。模式串在母串中是可以相互覆盖的。

做法:直接套用模板。在kmp中当j==m也就是模式串完全匹配时,ans++,且j = nexta[j]

 1 [cpp] view plain copy
 2 #include   
 3 #include    
 4 #include   
 5 using namespace std;  
 6 int nexta[1000006];  
 7 char t[1000006],s[1000006];  
 8 void getnexta(char s[])  
 9 {  
10     memset(nexta,0,sizeof(nexta));  
11     int n = strlen(s);  
12     int k = -1,j = 0;  
13     nexta[0] = -1;  
14     while(j < n )  
15     {  
16   
17         if(k == -1 || s[k] == s[j])  
18         {  
19             nexta[j + 1] = k + 1;  
20             j ++;  
21             k ++;  
22         }  
23         else  
24         {  
25             k = nexta[k];  
26         }  
27     }  
28   
29 }  
30 int kmp(char s[],char t[])//t模式串,s母串.此种为返回首次匹配的位置,不能匹配则返回-1.  
31 {  
32     getnexta(t);  
33     int ans = 0;  
34     int n = strlen(s),m = strlen(t);  
35     int i = 0,j = 0;  
36     while(i  m)  
37     {  
38         if(j == -1 || s[i] == t[j])  
39         {  
40             i ++;  
41             j ++;  
42         }  
43         else  
44         {  
45             j = nexta[j];  
46         }  
47         if(j == m)//根据题目要求改变  
48         {  
49             ans ++;  
50             j = nexta[j];  
51         }  
52     }  
53     return ans;  
54 }  
55 int main()  
56 {  
57    // freopen("in.txt","r",stdin);  
58     int T;  
59     scanf("%d",&T);  
60     while(T--)  
61     {  
62         scanf("%s%s",t,s);  
63         printf("%d\n",kmp(s,t));  
64     }  
65     return 0;  
66 }  

C.

题意:输入母串和模式串,以’#‘为结束。剪纸花,从母串中减去模式串问能剪出多少。这就意味着求解模式串的数量时不能重叠覆盖

做法:模板。在kmp中当j==m也就是模式串完全匹配时,ans++,且j = 0.要再次从头开始匹配

 1 [cpp] view plain copy
 2 #include   
 3 #include    
 4 #include   
 5 using namespace std;  
 6 int nexta[1006];  
 7 char t[1006],s[1006];  
 8 void getnexta(char s[])  
 9 {  
10     memset(nexta,0,sizeof(nexta));  
11     int n = strlen(s);  
12     int k = -1,j = 0;  
13     nexta[0] = -1;  
14     while(j < n )  
15     {  
16   
17         if(k == -1 || s[k] == s[j])  
18         {  
19             nexta[j + 1] = k + 1;  
20             j ++;  
21             k ++;  
22         }  
23         else  
24         {  
25             k = nexta[k];  
26         }  
27     }  
28   
29 }  
30 int kmp(char s[],char t[])//t模式串,s母串.此种为返回首次匹配的位置,不能匹配则返回-1.  
31 {  
32     getnexta(t);  
33     int ans = 0;  
34     int n = strlen(s),m = strlen(t);  
35     int i = 0,j = 0;  
36     while(i  m)  
37     {  
38         if(j == -1 || s[i] == t[j])  
39         {  
40             i ++;  
41             j ++;  
42         }  
43         else  
44         {  
45             j = nexta[j];  
46         }  
47         if(j == m)//根据题目要求改变  
48         {  
49             ans ++;  
50             j = 0;  
51         }  
52     }  
53     return ans;  
54 }  
55 int main()  
56 {  
57    // freopen("in.txt","r",stdin);  
58     while(1)  
59     {  
60         scanf("%s",s);  
61         if(strcmp(s,"#") == 0)  
62             break;  
63         scanf("%s",t);  
64         printf("%d\n",kmp(s,t));  
65     }  
66     return 0;  
67 } 

D.

题意:给T组数据,每组有一个字符串,只能在字符串的前面和后面增加字符,不能再中间增加,求要使这个字符串是周期循环的且周期的次数大于一,至少需要增加的字符数量。注意这个字符串是个手链,也就是说是增加字符后首位相连是周期的即可

做法:首先求最小循序节,考虑一种特殊情况就是nexta[n] = 0,这个时候前缀没有匹配后缀的地方,所以需要增加n个字符。求出最小循环节:n - nexta[n]。当n整除循环节时候,这时字符串已经是周期循环。当不整除时,最小循序节减去已经在字符串中的字符数目及ans = temp - (n % temp);(temp为最小循环节)

 1 [cpp] view plain copy
 2 #include   
 3 #include    
 4 #include   
 5 using namespace std;  
 6 int nexta[100005];  
 7 char s[100005];  
 8 void getnexta(char s[])  
 9 {  
10     memset(nexta,0,sizeof(nexta));  
11     int n = strlen(s);  
12     int k = -1,j = 0;  
13     nexta[0] = -1;  
14     while(j < n )  
15     {  
16         if(k == -1 || s[k] == s[j])  
17         {  
18             nexta[j + 1] = k + 1;  
19             j ++;  
20             k ++;  
21         }  
22         else  
23         {  
24             k = nexta[k];  
25         }  
26     }  
27 }  
28 int main()  
29 {  
30    // freopen("in.txt","r",stdin);  
31    int T,ans,n,temp;  
32    scanf("%d",&T);  
33     while(T --)  
34     {  
35         scanf("%s",s);  
36         n = strlen(s);  
37         getnexta(s);  
38         temp = n - nexta[n];//最小循环节  
39         if(temp == n)  
40         {  
41             ans = n;  
42         }  
43         else if(n % temp == 0)  
44         {  
45             ans = 0;  
46         }  
47         else  
48         {  
49             ans = temp - (n % temp);  
50         }  
51         printf("%d\n",ans);  
52     }  
53     return 0;  
54 }  

E.

题意:给字符串的长度和一个字符串。读到eof。求每个字符串中在i之前的位置是循环的且次数大于1,求这个位置i以及循环的次数

做法:求每个位置i的最小循环节,判断是否整除和个数大于1,并用除法的值求次数

 1 [cpp] view plain copy
 2 #include   
 3 #include   
 4 #include   
 5 using namespace std;  
 6 int nexta[1000002];  
 7 char s[1000002];  
 8 int n;  
 9 void getnexta()  
10 {  
11     memset(nexta,0,sizeof(nexta));  
12     int k = -1,j = 0;  
13     nexta[0] = -1;  
14     while(j < n )  
15     {  
16   
17         if(k == -1 || s[k] == s[j])  
18         {  
19             nexta[j + 1] = k + 1;  
20             j ++;  
21             k ++;  
22         }  
23         else  
24         {  
25             k = nexta[k];  
26         }  
27     }  
28   
29 }  
30 int main()  
31 {  
32    // freopen("in.txt","r",stdin);  
33         int t = 0,temp;  
34         while(1)  
35         {  
36             t ++;  
37             scanf("%d",&n);  
38             if(n == 0)  
39                 break;  
40             scanf("%s",s);  
41             printf("Test case #%d\n",t);  
42             getnexta();  
43             for(int i = 1; i <= n; i ++)  
44             {  
45         //cout<46         //cout<
47                 if(nexta[i] == 0)  
48                 {  
49                     continue;  
50                 }  
51                 else  
52                 {  
53                     temp = i - nexta[i] ;//循环小节的长度  
54                     if((i ) % temp == 0 && (i ) / temp  > 1)//这是由于nexta[i]表示的是i-1  
55                         printf("%d %d\n",i ,(i ) / temp);  
56                 }  
57   
58             }  
59         printf("\n");  
60         }  
61         return 0;  
62 }  
63   
64 /* 
65 a  a  b  a  a  b  a  a  b  a  a  b 
66 -1 0  1  0  1  2  3  4  5  6  7  8 
67 0  1  2  3  4  5  6  7  8  9  10 11 
68 */ 

F.

题意:每组给一个字符串,一直读到eof。这个字符串是重复写的AAAAAAA的一部分,求这个A最短是多少

做法:。。。。。。此题有问题,全网代码没有对的,我至少交了8+份代码

G.

题意:每组给以个字符串,一直读到‘.‘.字符串s = a^n,及都是由a构成的,求n的值

做法:求最小循环节,如果整除,那除得的数及为ans。如果不整除ans = 1

 1 [cpp] view plain copy
 2 #include   
 3 #include   
 4 #include   
 5 using namespace std;  
 6 int nexta[1000002];  
 7 char s[1000002];  
 8 int n;  
 9 void getnexta()  
10 {  
11     memset(nexta,0,sizeof(nexta));  
12     int k = -1,j = 0;  
13     nexta[0] = -1;  
14     while(j < n )  
15     {  
16   
17         if(k == -1 || s[k] == s[j])  
18         {  
19             nexta[j + 1] = k + 1;  
20             j ++;  
21             k ++;  
22         }  
23         else  
24         {  
25             k = nexta[k];  
26         }  
27     }  
28   
29 }  
30 int main()  
31 {  
32     //freopen("in.txt","r",stdin);  
33     int ans;  
34     while(1)  
35     {  
36         ans = 0;  
37         scanf("%s",s);  
38         if(strcmp(s,".") == 0)  
39             break;  
40         n = strlen(s);  
41         getnexta();  
42         if(n % (n - nexta[n])  == 0 )  
43             ans  = n / (n - nexta[n]);  
44         else   
45             ans = 1;  
46         printf("%d\n",ans);  
47     }  
48     return 0;  
49 }  
50   
51   
52 //ababa

H.

题意:每组一个字符串,读到eof结束。寻找i使得字符串的前缀等于后缀

做法:首先n(字符串的长度)肯定是,因为此时前缀和后缀是一样的。对nexta[n]进行递归。及i= nexta[i].当nexta[i] == 0时结束。因为是nexta找到的所以以i为结束的字符串后缀等于以n为结束的字符串的后缀。可以看看kmp算法讲解中的图,体会一下

 1 [cpp] view plain copy
 2 #include   
 3 #include   
 4 #include   
 5 using namespace std;  
 6 int nexta[1000002];  
 7 char s[1000002];  
 8 int ans[1000002];  
 9 int n;  
10 void getnexta()  
11 {  
12     memset(nexta,0,sizeof(nexta));  
13     int k = -1,j = 0;  
14     nexta[0] = -1;  
15     while(j < n )  
16     {  
17   
18         if(k == -1 || s[k] == s[j])  
19         {  
20             nexta[j + 1] = k + 1;  
21             j ++;  
22             k ++;  
23         }  
24         else  
25         {  
26             k = nexta[k];  
27         }  
28     }  
29   
30 }  
31   
32 int main()  
33 {  
34     //freopen("in.txt","r",stdin);  
35     int temp,k;  
36     while(scanf("%s",s) != EOF)  
37     {  
38         k = 0;  
39         if(strcmp(s,".") == 0)  
40             break;  
41         n = strlen(s);  
42         getnexta();  
43         temp = n;  
44         ans[k] = n;  
45         k ++;  
46         while(nexta[temp]!= -0)  
47         {  
48             temp = nexta[temp];  
49             ans[k] = temp;  
50             k ++;  
51         }  
52         for(int i = k -1; i > 0; i --)  
53             printf("%d ",ans[i]);  
54         printf("%d\n",ans[0]);  
55   
56     }  
57     return 0;  
58 }  
59   
60   
61 //ababa 

I.

题意:T组数据,每组m个DNA序列,每个DNA序列都有60个字符,且只由ACGT几个字母构成。判断m个DNA序列最长公共的子串是什么?如果有相同长度的公共子串,则输出字典序最小的。如果小于3输出“no ……”,大于等于3输出字符串

做法:对第一个DNA序列取从i开始到结尾的子串。与其他DNA序列进行匹配。因为是从前向后匹配,在kmp时做出改变,求出每个DNA序列和子串匹配的最长长度,再对所有最长长度取最短的那个。注意对长度相等时的处理。其中还用到strncpy,可以复制一定长度的字符串到指定字符串中。注意在最后加‘\0‘

  1 [cpp] view plain copy
  2 //直接枚举第一串的所有后缀,然后与后面的所有串进行比较,判断有几个字母是相同的即可  
  3 #include   
  4 #include   
  5 #include   
  6 #include   
  7 using namespace std;  
  8 int nexta[100];  
  9 char c[12][100];  
 10 char s[100];  
 11 int n,m,l;  
 12 void getnexta()  
 13 {  
 14     memset(nexta,0,sizeof(nexta));  
 15     int k = -1,j = 0;  
 16     nexta[0] = -1;  
 17     while(j < n )  
 18     {  
 19   
 20         if(k == -1 || s[k] == s[j])  
 21         {  
 22             nexta[j + 1] = k + 1;  
 23             j ++;  
 24             k ++;  
 25         }  
 26         else  
 27         {  
 28             k = nexta[k];  
 29         }  
 30     }  
 31   
 32 }  
 33 int kmp()  
 34 {  
 35     int k = 0,j = -1;  
 36     int maxx = 100,temp = 0;  
 37     for(int i = 1 ;i )  
 38     {  
 39         temp = 0;j = 0,k = 0;  
 40         while(j 60)  
 41         {  
 42             if(j == -1 || c[i][k] == s[j])  
 43             {  
 44                 j ++;  
 45                 k ++;  
 46   
 47             }  
 48   
 49             else  
 50                 j = nexta[j];  
 51             if(j > temp)//每个DNA序列和子串匹配的最长长度  
 52             {  
 53                 temp = j;  
 54             }  
 55   
 56         }  
 57         if(temp //所有DNA序列都和子串匹配的长度  
 58             maxx = temp;  
 59     }  
 60     return maxx;  
 61 }  
 62 int main()  
 63 {  
 64     //freopen("in.txt","r",stdin);  
 65     int T,temp,num;  
 66     n = 60;  
 67     scanf("%d",&T);  
 68     while(T--)  
 69     {  
 70         char result[100];  
 71         char t[100];  
 72         num = 0;  
 73         scanf("%d",&m);  
 74         for(int i = 0; i )  
 75         {  
 76             scanf("%s",&c[i]);  
 77         }  
 78         for(int i = 0; i <58; i ++)  
 79         {  
 80             l = 60 - i;  
 81             strcpy(s,c[0] + i);  
 82             getnexta();  
 83             temp = kmp();  
 84             if(num == temp)  
 85             {  
 86                 strncpy(t,c[0] + i,temp);  
 87                 if(t < result)  
 88                 {  
 89                     strcpy(result,t);  
 90                 }  
 91                 t[temp] = \0;  
 92             }  
 93             else if(num < temp)  
 94             {  
 95                 strncpy(result,c[0] + i,temp);  
 96                 result[temp] = \0;  
 97                 num = temp;  
 98             }  
 99         }  
100         //cout<
101         if(num >= 3)  
102         {  
103             printf("%s\n",result);  
104            // cout<
105         }  
106         else  
107             printf("no significant commonalities\n");  
108     }  
109     return 0;  
110 }  
111   
112   
113 //ababa 

J.

题意:每组给两个字符串以eof结尾。求s1的前缀,等于s2后缀的长度.如果长度不是零空格之后输出相同的部分,否则只输出零即可

做法:把s2接在s1后面,求nexta[n].注意求得的ans长度不能大于s1或s2

 1 [cpp] view plain copy
 2 /*考虑abcabcabcabc 
 3 abcabcabcabcabc这组数据也就是考虑当得数大于s1或s2时 
 4 */  
 5 #include   
 6 #include   
 7 #include   
 8 #include <string>  
 9 using namespace std;  
10 int nexta[100002];  
11 char s[100002];  
12 char a[50002];  
13 int n;  
14 void getnexta()  
15 {  
16     memset(nexta,0,sizeof(nexta));  
17     int k = -1,j = 0;  
18     nexta[0] = -1;  
19     while(j < n )  
20     {  
21   
22         if(k == -1 || s[k] == s[j])  
23         {  
24             nexta[j + 1] = k + 1;  
25             j ++;  
26             k ++;  
27         }  
28         else  
29         {  
30             k = nexta[k];  
31         }  
32     }  
33   
34 }  
35 int main()  
36 {  
37     // freopen("in.txt","r",stdin);  
38     while(scanf("%s%s",s,a) != EOF)  
39     {  
40         int ans = 0;  
41         strcat(s,a);  
42         int m = strlen(a);  
43         n = strlen(s);  
44         getnexta();  
45         //cout<46         //cout<47         // cout<
48         ans = nexta[n];  
49         //cout<
50         if(ans != 0)  
51         {  
52             if(ans > n || ans > m)  
53                 ans = min(n - m,m);  
54             for(int i = 0; i )  
55                 printf("%c",s[i]);  
56             printf(" %d\n",ans);  
57   
58         }  
59         else  
60             printf("0\n");  
61     }  
62     return 0;  
63 }  

K

题意:给T组数据,每组数据给一个长度为n的字符串s。求字符串每个前缀出现的次数,结果mod 10007

做法:dp[i]表示的是长度为i的字符串的前缀的个数。dp[i] = dp[nexta[i]] + 1。以i-1为结尾的后缀的个数是next[i],也是前缀的长度。这个前缀的长度中字符串本身的前缀出现的次数。因为以i - 1为后缀的字符串中都又出现了一次

ababa

dp[1] = 1 a

dp[2] = 1 ab

dp[3] = 2 aba a

dp[4] = 2 abab ab

dp[5] = 3 ababa aba a

 1 [cpp] view plain copy
 2 #include   
 3 #include   
 4 #include   
 5 #include   
 6 #include   
 7 #include   
 8 #include   
 9 #include   
10 #include   
11 #include <string>  
12   
13 using namespace std;  
14 char s[200005];  
15 int nexta[200005];  
16 int dp[200005];  
17 int n;  
18 void getnext()  
19 {  
20     int j = 0,k = -1;  
21     nexta[0] = -1;  
22     while(j < n)  
23     {  
24         if(k == -1 || s[j] == s[k])  
25         {  
26             nexta[j + 1] = k + 1;  
27             j ++;  
28             k ++;  
29         }  
30         else  
31         {  
32             k = nexta[k];  
33         }  
34   
35     }  
36 }  
37 int main()  
38 {  
39     //freopen("in.txt","r",stdin);  
40     int T,ans;  
41     scanf("%d",&T);  
42     while(T--)  
43     {  
44         scanf("%d",&n);  
45         scanf("%s",s);  
46         getnext();  
47         memset(dp,0,sizeof(dp));  
48         ans = 0;  
49         for(int i = 1;i <= n; i ++)  
50         {  
51             dp[i] = dp[nexta[i]] + 1;  
52             ans += dp[i] % 10007;  
53         }  
54         printf("%d\n",ans % 10007);  
55     }  
56     return 0;  
57 } 

L.

题意:给T组数据,每组数据第一行是26个字母表示[a,z]所对应的密文字母。第二行的字符串由两部分组成,第一部分是密文部分,第二部分是明文部分。明文部分可能是不完整的,也可能是完整的输出完整的明文部分

做法:先输出第二行的全部字符串。然后对整个字符串进行变化,把密文部分转化为明文部分。原串密文部分的长度一定大于等于明文部分。明文部分最长就是从整个字符串的一半开始的。将转化后的字符串与未转化之前的字符串的后半部分进行匹配。匹配到的返回结果就是原字符串中明文的个数:temp。则密文的个数为n - temp.实际应该的长度为2 * n - 2 * temp.应该输出的长度为:2 * n - 2 * temp - n.从转换后的字符串的temp位开始直接输出即可。从该位置开始到字符串的长度减去该位置都是待输出的不完整的字符串。其实质就是用完整的明文串,与题目中给出的不一定完整的明文串进行匹配。注意其中完整的是模式串,不完整的是所谓的母串。模式串是从头开始匹配的。而母串不是

提一下如何将密文转化为明文,将第一行该位置对应的字母转化为该位置i转化为字母(i + ‘a‘)

ps:这也就意味着,不要从头开始匹配,是母串。而普通kmp的模式串一定要是从头开始匹配的。

abcdefghijklmnopqrstuvwxyz

abcdab

abcdab

 1 [cpp] view plain copy
 2 //密文和明文前后两端是重复的  
 3 #include   
 4 #include   
 5 #include   
 6 #include   
 7 #include   
 8 #include   
 9 #include   
10 #include   
11 #include   
12 #include <string>  
13   
14 using namespace std;  
15 map<char,char>mapp;  
16 char s[100005];  
17 char s2[100005];  
18 int nexta[100005];  
19 char c[30];  
20 int n;  
21 void getnext()  
22 {  
23     memset(nexta,0,sizeof(nexta));  
24     int j = 0,k = -1;  
25     nexta[0] = -1;  
26     while(j < n)  
27     {  
28         if(k == -1 || s[j] == s[k])  
29         {  
30             nexta[j + 1] = k + 1;  
31             j ++;  
32             k ++;  
33         }  
34         else  
35         {  
36             k = nexta[k];  
37         }  
38   
39     }  
40 }  
41 int kmp()  
42 {  
43     int la = strlen(s2),lb = strlen(s);  
44     getnext();  
45     int i = 0, j = 0;  
46     while(i  lb)  
47     {  
48         if(j == -1 || s2[i] == s[j])  
49         {  
50             i ++;  
51             j ++;  
52   
53         if(i == la)  
54             return j;  
55         }  
56         else  
57         {  
58             j = nexta[j];  
59         }  
60     }  
61     return 0;  
62 }  
63 int main()  
64 {  
65    //freopen("in.txt","r",stdin);  
66     int T;  
67     scanf("%d",&T);  
68     while(T--)  
69     {  
70         scanf("%s%s",c,s);  
71         printf("%s",s);  
72         n = strlen(s);  
73         int m = (n + 1) / 2;  
74         strcpy(s2,s + m);  
75   
76         for(int i = 0; i <26; i ++)  
77         {  
78             mapp[c[i]] = a + i;  
79         }  
80         for(int i = 0; i )  
81         {  
82             s[i] = mapp[s[i]];  
83         }  
84         int temp = kmp();  
85        // cout<
86         for(int i =temp; i //n-temp密文长度  
87         {  
88             printf("%c",s[i]);  
89         }  
90         printf("\n");  
91     }  
92     return 0;  
93 }

Q.

题意:每组n个字符串,以eof结束。求每个字符串中满足S[i]=S[i+P] for i in [0..SIZE(S)-p-1],的位置。

做法:其实还是前缀与后缀相等,其中p是后缀开始的地方。递归nexta即可。因为nexta递归得到的以i为结束后缀等于前缀,等于整个长度的后缀.注意p的大小是n - nexta[n](nexta[n]是后缀的长度,n - nexta[n]就是后缀开始的位置了)

 1 #include 
 2 #include 
 3 #include 
 4 using namespace std;
 5 int nexta[1000005];
 6 char s[1000005];
 7 int ans[1000005];
 8 int n;
 9 void getnexta()
10 {
11     int j = 0,k = -1;
12     nexta[0] = -1;
13     while(j < n)
14     {
15         if(k == -1 || s[j] == s[k])
16         {
17             nexta[j + 1] = k + 1;
18             j ++;
19             k ++;
20         }
21         else
22         {
23             k = nexta[k];
24         }
25     }
26 }
27 int main()
28 {
29   //  freopen("in.txt","r",stdin);
30     int T;
31     scanf("%d",&T);
32     for(int t=1; t<= T; t++)
33     {
34         scanf("%s",s);
35         n = strlen(s);
36         getnexta();
37         int a = n;
38         int num = 0;
39         while(nexta[a] != -1)
40         {
41             ans[num] = n - nexta[a];
42             num ++;
43             a = nexta[a];
44         }
45         printf("Case #%d: %d\n",t,num);
46         for(int i = 0; i 1; i ++)
47         {
48             printf("%d ",ans[i]);
49         }
50         printf("%d\n",ans[num - 1]);
51     }
52     return 0;
53 }

Z.

题意:n个字符串,每个字符串都可以写成EAEBE的形式,其中E可以为空,寻找最长的E

做法:首先我们很容易知道E最长长度为nexta[n],然后判断中间的那个E是否存在,设E的长度为i。从开头位置加1开始遍历(i+1),到<(n - i)为止,如果有next[j] == i那么可以判断这个长度的E存在。从E可能的最大长度开始遍历

 1 [cpp] view plain copy
 2 #include  
 3 #include  
 4 #include  
 5 using namespace std;  
 6 char s[1000005];  
 7 char t[1000005];  
 8 int nexta[1000005];  
 9 int n;  
10 void getnexta()  
11 {  
12     memset(nexta,0,sizeof(nexta));  
13     nexta[0] = -1;  
14     int k = -1,j = 0;  
15     while(j < n)  
16     {  
17         if(k == -1 || s[k] == s[j])  
18         {  
19             nexta[j + 1] = k + 1;  
20             j ++;  
21             k ++;  
22         }  
23         else  
24         k = nexta[k];  
25     }  
26 }  
27   
28 int main()  
29 {  
30   //  freopen("in.txt","r",stdin);  
31     int T;  
32     scanf("%d",&T);  
33     while(T--)  
34     {  
35         scanf("%s",s);  
36         n = strlen(s);  
37         getnexta();  
38         //cout<
39         int ans = 0,i;  
40         bool flag ;  
41         for(i = min(n / 3 - 1,nexta[n] - 1);i >= 0;i --)  
42         {  
43             //cout<
44             for(int j = i + 1; j )  
45             {  
46                 flag = false;  
47                 if(nexta[j] == i )  
48                 {  
49                     ans = i + 1;  
50                     flag = true;  
51                     break;  
52                 }  
53             }  
54             if(flag)  
55                 break;  
56         }  
57         if(i == -1)  
58             ans = 0;  
59         cout<endl;  
60     }  
61     return 0;  
62 }  

使用高级算法会减少思维难度,相比较来说,高级算法虽然难度大,但是实用性更强

KMP算法应用举例


推荐阅读
  • [c++基础]STL
    cppfig15_10.cppincludeincludeusingnamespacestd;templatevoidprintVector(constvector&integer ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • 自动验证时页面显示问题的解决方法
    在使用自动验证功能时,页面未能正确显示错误信息。通过使用 `dump($info->getError())` 可以帮助诊断和解决问题。 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 本文详细介绍了如何解决DNS服务器配置转发无法解析的问题,包括编辑主配置文件和重启域名服务的具体步骤。 ... [详细]
  • importpymysql#一、直接连接mysql数据库'''coonpymysql.connect(host'192.168.*.*',u ... [详细]
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • ZooKeeper 入门指南
    本文将详细介绍ZooKeeper的工作机制、特点、数据结构以及常见的应用场景,包括统一命名服务、统一配置管理、统一集群管理、服务器动态上下线和软负载均衡。 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • Framework7:构建跨平台移动应用的高效框架
    Framework7 是一个开源免费的框架,适用于开发混合移动应用(原生与HTML混合)或iOS&Android风格的Web应用。此外,它还可以作为原型开发工具,帮助开发者快速创建应用原型。 ... [详细]
  • 本文介绍了如何使用 CMD 批处理脚本进行文件操作,包括将指定目录下的 PHP 文件重命名为 HTML 文件,并将这些文件复制到另一个目录。 ... [详细]
  • 两个条件,组合控制#if($query_string~*modviewthread&t(&extra(.*)))?$)#{#set$itid$1;#rewrite^ ... [详细]
  • 本文详细介绍了DMA控制器如何通过映射表处理来自外设的请求,包括映射表的设计和实现方法。 ... [详细]
  • 解决Win10下MySQL连接问题:Navicat 2003无法连接到本地MySQL服务器(10061)
    本文介绍如何在Windows 10环境下解决Navicat 2003无法连接到本地MySQL服务器的问题,包括启动MySQL服务和检查配置文件的方法。 ... [详细]
author-avatar
mobiledu2502882333
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有