zoukankan      html  css  js  c++  java
  • CF #93 div1 B. Password KMP/Z

    题目链接:http://codeforces.com/problemset/problem/126/B

    大意:给一个字符串,问最长的既是前缀又是后缀又是中缀(这里指在内部出现)的子串。

    我自己的做法是用KMP的next数组,对所有既是前缀又是中缀的位置计数,再从next[n]开始走next,也即枚举所有既是前缀又是后缀的子串,看cnt[i]是否大于0,如果大于0则说明作为中缀出现过(也即有大于i的某个位置的next为i)

     1 #include <iostream>
     2 #include <vector>
     3 #include <algorithm>
     4 #include <string>
     5 #include <string.h>
     6 #include <stdio.h>
     7 #include <math.h>
     8 #include <stdlib.h>
     9 #include <queue>
    10 #include <stack>
    11 #include <map>
    12 #include <set>
    13 
    14 using namespace std;
    15 
    16 const int N=1e6+12345;
    17 char s[N];
    18 int next[N];
    19 int cnt[N];
    20 void getNext(char *word,int n=0){
    21     n=(n==0)?strlen(word):n;
    22     memset(next,0,sizeof(next));
    23     int i,j;
    24     for (i=1;i<n;i++){
    25         j=i;
    26         while (j){
    27             j=next[j];
    28             if (word[i]==word[j]){
    29                 next[i+1]=j+1;
    30                 break;
    31             }
    32         }
    33     }
    34 }
    35 int main () {
    36     scanf("%s",s);
    37     int n=strlen(s);
    38     getNext(s,n);
    39     for (int i=2;i<n;i++)
    40         cnt[next[i]]++;
    41     if (next[n]==0)
    42         puts("Just a legend");
    43     else {
    44         for (int i=next[n];i;i=next[i]) {
    45             if (cnt[i]) {
    46                 for (int j=0;j<i;j++)
    47                     printf("%c",s[j]);
    48                 puts("");
    49                 return 0;
    50             }
    51         }
    52         puts("Just a legend");
    53     }
    54     return 0;
    55 }
    View Code

    还有一种枚举方法是扫描所有可能的中缀末位,取next[i]的最大值,也即求出最大的既是前缀又是中缀的子串,再从next[n]开始走next,第一次走到0<next[i]<=len时,也即找到了子串。

     1 #include <iostream>
     2 #include <vector>
     3 #include <algorithm>
     4 #include <string>
     5 #include <string.h>
     6 #include <stdio.h>
     7 #include <math.h>
     8 #include <stdlib.h>
     9 #include <queue>
    10 #include <stack>
    11 #include <map>
    12 #include <set>
    13 
    14 using namespace std;
    15 
    16 const int N=1e6+12345;
    17 char s[N];
    18 int next[N];
    19 void getNext(char *word,int n=0){
    20     n=(n==0)?strlen(word):n;
    21     memset(next,0,sizeof(next));
    22     int i,j;
    23     for (i=1;i<n;i++){
    24         j=i;
    25         while (j){
    26             j=next[j];
    27             if (word[i]==word[j]){
    28                 next[i+1]=j+1;
    29                 break;
    30             }
    31         }
    32     }
    33 }
    34 int main () {
    35     scanf("%s",s);
    36     int n=strlen(s);
    37     getNext(s,n);
    38     int len=0;
    39     for (int i=2;i<n;i++)
    40         len=max(len,next[i]);
    41     for (int i=next[n];i>0;i=next[i]) {
    42         if (i>len) continue;
    43         for (int j=0;j<i;j++)
    44             printf("%c",s[j]);
    45         puts("");
    46         return 0;
    47     }
    48     puts("Just a legend");
    49     return 0;
    50 }
    View Code

    第三种方法是用z算法,也就是算出每个位置与本串的最长公共前缀。再枚举所有后缀,check当前后缀是否也是前缀,如果是的话,则看之前是否有z[i]也就是与本串的LCP大于当前后缀长度,如果有,则当前后缀也一定可以作为中缀出现,当前后缀是最长的符合题意的子串。

     1 #include <iostream>
     2 #include <vector>
     3 #include <algorithm>
     4 #include <string>
     5 #include <string.h>
     6 #include <stdio.h>
     7 #include <math.h>
     8 #include <stdlib.h>
     9 #include <queue>
    10 #include <stack>
    11 #include <map>
    12 #include <set>
    13 
    14 using namespace std;
    15 
    16 const int N=1e6+12345;
    17 char s[N];
    18 int z[N];
    19 void Z_match(char *s,int n=0) {
    20     n=(n==0)?strlen(s):n;
    21     z[0]=n;
    22     int l=0,r=0;
    23     for (int i=1;i<n;i++) {
    24         if (i>r) {
    25             l=i,r=i;
    26             while (r<n&&s[r-i]==s[r]) r++;
    27             z[i]=r-l;
    28             r--;
    29         }
    30         else {
    31             int k=i-l;
    32             if (z[k]<r-i+1)
    33                 z[i]=z[k];
    34             else {
    35                 l=i;
    36                 while (r<n&&s[r-i]==s[r]) r++;
    37                 z[i]=r-l;
    38                 r--;
    39             }
    40         }
    41     }
    42 }
    43 int main () {
    44     scanf("%s",s);
    45     int n=strlen(s);
    46     Z_match(s,n);
    47     int ret=0,maxZ=0;
    48     for (int i=1;i<n;i++) {
    49         if (z[i]==n-i) {
    50             if (maxZ>=n-i) {
    51                 ret=n-i;
    52                 break;
    53             }
    54         }
    55         maxZ=max(maxZ,z[i]);
    56     }
    57     if (ret==0)
    58         puts("Just a legend");
    59     else {
    60         for (int i=0;i<ret;i++)
    61             printf("%c",s[i]);
    62         puts("");
    63     }
    64     return 0;
    65 }
    View Code
  • 相关阅读:
    RESTful风格的API
    案例:toDoList
    jQuery中的Ajax
    php 使用kafka
    crontab不执行
    php两种实现守护进程的方式
    crontab不执行脚本,手动调测又没有任何问题
    centos7 安装跳板机(堡垒机)
    Ubuntu修改默认键盘布局的方法
    openresty nginx升级版
  • 原文地址:https://www.cnblogs.com/micrari/p/5232576.html
Copyright © 2011-2022 走看看