热门标签 | 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算法应用举例


推荐阅读
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
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社区 版权所有