:::info 参考博文:https://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html
视频:https://www.acwing.com/video/259/
例题:https://www.acwing.com/problem/content/833/ :::

BF算法(暴力)

思想

BF算法就是暴力解,双重循环,有字符不匹配就回溯(i=i-j+1)
image.png

代码

  1. int BFMatch(char *s,char *p)
  2. {
  3. int i,j;
  4. i=0;
  5. while(i<strlen(s))
  6. {
  7. j=0;
  8. while(s[i]==p[j]&&j<strlen(p))
  9. {
  10. i++;
  11. j++;
  12. }
  13. if(j==strlen(p))
  14. return i-strlen(p);
  15. i=i-j+1; //指针i回溯
  16. }
  17. return -1;
  18. }

KMP O(n)

思想

KMP算法解决的主要是优化BF算法,BF算法中第五趟不匹配时,第六趟j可以直接从2开始,不需要从0开始,这种多余的匹配过程在kmp中取消了。kmp不再进行i=i-j+1的指针回溯过程,只需要每次考虑j指针即可
image.pngimage.png

next数组思想

利用了最大的后缀等于前缀的思想
首先来了解一下什么是前缀,什么是后缀。
abacab为例
前缀:a``ab``aba``abac``abaca
后缀:b``ab``cab``acab``bacab
可以看出前后缀都不包括本身,其中最大的后缀等于前缀的意思是最长的相等的前后缀,在这个例子中是ab

代码

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 100010, M = 1000010;
  4. int n, m;
  5. int ne[N];
  6. char s[M], p[N];
  7. int main()
  8. {
  9. cin >> n >> p + 1 >> m >> s + 1;
  10. // 求解next数组
  11. // 因为j=0是空的,j=1是第一个数,ne[1]=0,所以j从2开始
  12. for (int j = 2, k = 0; j <= n; j ++ )
  13. {
  14. // 如果不匹配则一直往后退。退到退无可退(k!=0)
  15. while (k!=0 && p[j] != p[k + 1]) k = ne[k];
  16. if (p[j] == p[k + 1]) k ++ ;
  17. ne[j] = k;
  18. }
  19. // 匹配
  20. for (int i = 1, j = 0; i <= m; i ++ )
  21. {
  22. // 如果不匹配则一直往后退。退到退无可退(j!=0)
  23. while (j!=0 && s[i] != p[j + 1]) j = ne[j];
  24. // 如果匹配成功则看下一个
  25. if (s[i] == p[j + 1]) j ++ ;
  26. if (j == n)
  27. {
  28. //因为匹配成功后,p[j + 1]相当于是空字符,一定不匹配s[]中的任何字符,所以可以更新一次j
  29. // 如果此处不更新也可以,因为p[j + 1]相当于是空字符,一定不匹配s[]中的任何字符,在下一次循环中会进行j=ne[j]操作
  30. // 为了减少循环次数可以更新一次j
  31. j = ne[j];
  32. // 匹配成功后的逻辑
  33. printf("%d ", i - n);
  34. }
  35. }
  36. return 0;
  37. }