ACM常用模板——字符串匹配——KMP

模板:

  1. #define LL long long
  2. #define MS(a,b) memset(a,b,sizeof(a))
  3. #define FI(a,b) fill(a,a+maxn,b)
  4. #define sf(n) scanf("%d",&n)
  5. #define sf2(a,b) scanf("%d%d",&a,&b)
  6. #define pf(n) printf("%d\n",n)
  7. #define ffr(i,n) for(i=0;i<n;i++)
  8. /*
  9. s:abcdabcadcabcdcab
  10. p: abcdcab
  11. next:-1000001
  12. */
  13. using namespace std;
  14. void getNext(const std::string& p, std::vector<int>& ne)
  15. {
  16. ne.resize(p.size());
  17. ne[0] = -1;
  18. int i = 0, j = -1;
  19. while (i != p.size() - 1)
  20. {
  21. if (j == -1 || p[i] == p[j])
  22. {
  23. ++i;
  24. ++j;
  25. ne[i] = j;
  26. }
  27. else
  28. {
  29. j = ne[j];
  30. }
  31. }
  32. }
  33. int kmp(const std::string& s, const std::string& p, const int sIndex = 0)//返回下标 从0开始
  34. {
  35. std::vector<int>ne(p.size());
  36. getNext(p, ne);//获取next数组,保存到vector中
  37. int i = sIndex, j = 0;
  38. while(i != s.length() && j != p.length())
  39. {
  40. if (j == -1 || s[i] == p[j])
  41. {
  42. ++i;
  43. ++j;
  44. }
  45. else
  46. {
  47. j = ne[j];
  48. }
  49. }
  50. return j == p.length() ? i - j: -1;
  51. }
  52. int main()
  53. {
  54. string a,b;
  55. while(cin>>a>>b){
  56. cout<<kmp(a,b,0)<<endl;//返回匹配的下标
  57. }
  58. return 0;
  59. }

hdu1686 模型:统计字串在母串中出现的次数(字母可重复)

  1. #include <stdio.h>
  2. #include <string.h>
  3. int next[10005];
  4. char str1[1000005],str2[10005];
  5. int cnt;
  6. void get_next(int len2)//生成next数组
  7. {
  8. int i = 0,j = -1;
  9. next[0] = -1;
  10. while (i<len2)
  11. {
  12. if(j == -1 || str2[i] == str2[j])
  13. {
  14. i++;
  15. j++;
  16. if (str2[i]!=str2[j])
  17. next[i] = j;
  18. else
  19. next[i] = next[j];
  20. }
  21. else
  22. j = next[j];
  23. }
  24. }
  25. int kmp(int len1,int len2)//kmp算法
  26. {
  27. int i=0,j=0;
  28. get_next(len2);
  29. while(i<len1)
  30. {
  31. if(j==-1||str1[i]==str2[j])
  32. {
  33. ++i;
  34. ++j;
  35. }
  36. else
  37. j=next[j];
  38. if(j == len2)
  39. {
  40. cnt++;
  41. j = next[j];
  42. }
  43. }
  44. }
  45. int main()
  46. {
  47. int n;
  48. int len1,len2;
  49. scanf("%d",&n);
  50. getchar();
  51. while(n--)
  52. {
  53. gets(str2);
  54. gets(str1);
  55. len1 = strlen(str1);
  56. len2 = strlen(str2);
  57. cnt = 0;
  58. kmp(len1,len2);
  59. printf("%d\n",cnt);
  60. }
  61. return 0;
  62. }

next数组应用:前缀个数 以下标i为终点重复子串的个数
aabaabaabaab

2 26 29 312 4

  1. void getNext(const std::string& p, std::vector<int>& next)
  2. {
  3. next.resize(p.size()+1);
  4. next[0] = -1;
  5. int i = 0, j = -1;
  6. while (i != p.size())
  7. {
  8. if (j == -1 || p[i] == p[j])
  9. {
  10. ++i;
  11. ++j;
  12. next[i] = j;
  13. if(i%(i-next[i])==0&&i/(i-next[i])>1){
  14. printf("%d %d\n",i,i/(i-next[i]));
  15. }
  16. }
  17. else
  18. {
  19. j = next[j];
  20. }
  21. }
  22. }
  23. int main()
  24. {
  25. int n,i,Case=1;
  26. char s[maxn];
  27. while(~sf(n)&&n){
  28. scanf("%s",s);
  29. vector<int>next(strlen(s)+1);
  30. printf("Test case #%d\n",Case++);
  31. getNext(s, next);
  32. printf("\n");
  33. }
  34. return 0;
  35. }

循环节:

  1. #include<iostream>
  2. #include<string.h>
  3. using namespace std;
  4. int next[1000005];
  5. char s[1000005];
  6. void getnext()
  7. {
  8. int i=0,j=-1;
  9. next[0]=-1;
  10. int len=strlen(s);
  11. while(i<len)
  12. {
  13. if(s[i]==s[j]||j==-1)
  14. {
  15. i++;
  16. j++;
  17. next[i]=j;
  18. }
  19. else
  20. j=next[j];
  21. }
  22. }
  23. int main()
  24. {
  25. while(scanf("%s",s)>0)
  26. {
  27. if(s[0]=='.')
  28. break;
  29. int len=strlen(s);
  30. getnext();
  31. if(len%(len-next[len])==0)
  32. printf("%d\n",len/(len-next[len]));
  33. else
  34. printf("1\n");
  35. }
  36. return 0;
  37. }
    原文作者:KMP算法
    原文地址: https://blog.csdn.net/kukajenny/article/details/49870927
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞