• kmp与扩展kmp(板子整理)


    kmp

    next[i]:求模式串中前缀和后缀的最长公共前缀

    即对于[1,i]来说,求最大的x,使s[1,x]等于s[i-x+1,i]

    例题

    以hdu1711为例,

    统计a串中第一个出现b串的起始下标,

    即若第一个出现b串的区间是[l,r],输出l

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int a[1000005],b[10005];
    6. int n,m;
    7. int nex[10005];
    8. void kmppre(){
    9. int i=0,j=nex[0]=-1;
    10. while(i
    11. while(j!=-1&&b[i]!=b[j])j=nex[j];
    12. nex[++i]=++j;
    13. }
    14. }
    15. int kmpcount(){
    16. int i,j,ans=0;
    17. kmppre();
    18. i=j=0;
    19. while(i
    20. while(j!=-1&&a[i]!=b[j])j=nex[j];
    21. i++;j++;
    22. if(j==m)return i-j+1;
    23. }
    24. return -1;
    25. }
    26. int main(){
    27. int T;
    28. scanf("%d",&T);
    29. while(T--){
    30. scanf("%d%d",&n,&m);
    31. for(int i=0;iscanf("%d",&a[i]);
    32. for(int i=0;iscanf("%d",&b[i]);
    33. printf("%d\n",kmpcount());
    34. }
    35. return 0;
    36. }

    最小表示法与最大表示法

    最小表示法:

    对于串bca来说,其循环串abc,bca,cab中字典序最小的那个,串abc,即为最小表示

    最大表示法同理

    hdu3374,用kmp求一个串的最小表示法

    1. //一个串在表示法里出现了几次 等于这个串的循环节在串中出现的次数
    2. //考虑一串珠子 往后转循环节个长度 还能得到一个与原串相同的串 这就是循环节的定义
    3. //即循环节出现的次数 即为表示法中出现的次数
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. const int INF=0x3f3f3f3f;
    16. const int MOD=1e9+7;
    17. const double eps=1e-7;
    18. typedef long long ll;
    19. #define vi vector
    20. #define si set
    21. #define pii pair
    22. #define pi acos(-1.0)
    23. #define pb push_back
    24. #define mp make_pair
    25. #define lowbit(x) (x&(-x))
    26. #define sci(x) scanf("%d",&(x))
    27. #define scll(x) scanf("%lld",&(x))
    28. #define sclf(x) scanf("%lf",&(x))
    29. #define pri(x) printf("%d",(x))
    30. #define rep(i,j,k) for(int i=j;i<=k;++i)
    31. #define per(i,j,k) for(int i=j;i>=k;--i)
    32. #define mem(a,b) memset(a,b,sizeof(a))
    33. using namespace std;
    34. string s;
    35. int net[1000005];
    36. int getminmax(int flag,string s)//min是0 max是1 注意flag的应用
    37. {
    38. int n=s.size();
    39. int i=0,j=1,k=0,t;
    40. while(i
    41. {
    42. t=s[(i+k)%n]-s[(j+k)%n];
    43. if(!t)k++;
    44. else
    45. {
    46. if(!flag)t>0?i+=k+1:j+=k+1;
    47. else t>0?j+=k+1:i+=k+1;
    48. if(i==j)j++;
    49. k=0;
    50. }
    51. }
    52. return i
    53. }
    54. void kmppre(string s)
    55. {
    56. int i,j,n=s.size();
    57. i=0,j=net[0]=-1;
    58. while(i
    59. {
    60. while(j!=-1&&s[i]!=s[j])j=net[j];
    61. net[++i]=++j;
    62. }
    63. }
    64. void init(int &t)
    65. {
    66. mem(net,0);
    67. t=1;
    68. }
    69. int main()
    70. {
    71. int len,minn,maxx,t;
    72. while(cin>>s)
    73. {
    74. init(t);
    75. kmppre(s);
    76. len=s.size();
    77. minn=getminmax(0,s);//求最小表示法
    78. maxx=getminmax(1,s);//求最大表示法
    79. if(len%(len-net[len])==0)t=len/(len-net[len]);
    80. printf("%d %d %d %d\n",1+minn,t,1+maxx,t);//minn的pos和maxx的pos
    81. }
    82. return 0;
    83. }

    循环节

    设m为串长,则m-next[m]是一个循环节,

    m-next[next[m]]也是循环节,以此类推…

    可以不断跳next数组获取到所有循环节

    这些循环节并不是都能整除m,

    能整除m的最短循环节最为常用

    扩展kmp(Z函数)

    next[i]:求模式串中前缀和后缀的最长公共前缀

    即对于[1,i]来说,求最大的x,使s[1,x]等于s[i-x+1,i]

    extend[i]: 求文本串中以i开始的一个后缀,和模式串中的前缀的最长公共前缀

    即,对于文本串t[1,m]和模式串s[1,n]来说,

    求最大的x,使得t[i,i+x-1]等于s[1,x]

    替代方案

    kmp可以取巧替代exkmp,并且实际效果比kmp快

    t=s+'#'+t,即模式串在最前,中间用未出现的字符分隔,文本串在最后

    则数组后半部分的next[i]即为所求

    例题

    以poj3080为例,

    多个字符串,问你这几个字符串的最长公共子串是哪个,

    如果有多个,输出字典序最大的那个,

    如果最长的公共子串长度小于3,输出no significant commonalities

    其实有点强行用exkmp的意思,暴力枚举每个串判是否在其他的串中存在,kmp也可以

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define sci(x) scanf("%d",&(x))
    8. #define scs(x) scanf("%s",(x))
    9. #define scll(x) scanf("%lld",&(x))
    10. #define sclf(x) scanf("%lf",&(x))
    11. #define rep(i,j,k) for(int i=j;i<=k;++i)
    12. #define mem(a,b) memset(a,b,sizeof(a))
    13. using namespace std;
    14. char a[15][65];
    15. int net[65],ex[65];
    16. char s1[65],s2[65],tmp[65];
    17. void extkmppre(char s[])
    18. {
    19. int i=0,j,pos,len=strlen(s);
    20. net[0]=len;
    21. while(i+11])i++;
    22. net[1]=i,pos=1;
    23. rep(i,2,len-1)
    24. {
    25. if(net[i-pos]+i
    26. {
    27. net[i]=net[i-pos];
    28. }
    29. else
    30. {
    31. j=net[pos]+pos-i;
    32. if(j<0)j=0;
    33. while(i+j
    34. net[i]=j,pos=i;
    35. }
    36. }
    37. }
    38. bool extkmp(char s1[],char s2[])
    39. {
    40. int i=0,j,pos,l1=strlen(s1),l2=strlen(s2);
    41. extkmppre(s2);
    42. while(i
    43. ex[0]=i,pos=0;
    44. if(ex[0]==l2)return 1;
    45. rep(i,1,l1-1)
    46. {
    47. if(net[i-pos]+i
    48. {
    49. ex[i]=net[i-pos];
    50. }
    51. else
    52. {
    53. j=ex[pos]+pos-i;
    54. if(j<0)j=0;
    55. while(i+j
    56. ex[i]=j,pos=i;
    57. }
    58. if(ex[i]==l2)return 1;
    59. }
    60. return 0;
    61. }
    62. void cpy(char a[],char b[],int l,int r)
    63. {
    64. rep(i,l,r)a[i-l]=b[i];
    65. a[r-l+1]='\0';
    66. }
    67. int main()
    68. {
    69. int t;
    70. sci(t);
    71. while(t--)
    72. {
    73. mem(a,0);
    74. mem(tmp,0);
    75. int m,maxlen=0,l,r;
    76. sci(m);
    77. rep(i,0,m-1)
    78. scs(a[i]);
    79. rep(i,0,59)
    80. {
    81. rep(j,i+2,59)
    82. {
    83. if(j-i+1continue;//剪枝
    84. bool flag=1;
    85. cpy(tmp,a[0],i,j);
    86. rep(k,1,m-1)
    87. {
    88. if(extkmp(a[k],tmp))continue;
    89. flag=0;
    90. break;
    91. }
    92. if(flag)
    93. {
    94. if(j-i+1>maxlen)
    95. {
    96. maxlen=j-i+1;
    97. l=i,r=j;
    98. }
    99. else if(j-i+1==maxlen)
    100. {
    101. rep(k,0,maxlen-1)
    102. {
    103. if(a[0][k+i]>a[0][k+l])break;
    104. if(a[0][k+i]0][k+l])
    105. {
    106. l=i,r=j;
    107. break;
    108. }
    109. }
    110. }
    111. }
    112. }
    113. }
    114. if(maxlen<3)puts("no significant commonalities");
    115. else
    116. {
    117. cpy(tmp,a[0],l,r);
    118. printf("%s\n",tmp);
    119. }
    120. }
    121. return 0;
    122. }

  • 相关阅读:
    3-egg-TS-通用后端管理注册系统-图形验证码
    串行原理编程,中文编程工具中的串行构件,串行连接操作简单
    ELK:开源搜索与分析技术栈(2)
    UDP内核发包流程
    位逻辑运算符
    MySQL的索引原理
    高效Go编程: encoding/csv标准库深度解析
    JVM的垃圾回收机制
    香港日本服务器好机推荐CN2三网直连高速又稳定
    关于ASPICE 4.0评估师资质更新的说明-亚远景科技
  • 原文地址:https://blog.csdn.net/Code92007/article/details/127991986