思路:

首先计算出模板字符串每个位置的最长公共前后缀,通过最长公共前后缀可以在和原始字符串进行比较的时候只需要O(n)的时间比较完成。

而【计算模板字符串每个位置的最长公共前后缀】,【计算原始字符串和模板字符串的最长匹配公共前缀】是一样的做法。前者,模板字符串的前缀和当前后缀进行比较,记录每个位置匹配的最长前后缀,当前位置前缀串和后缀串相等的时候,其最长匹配前缀就是之前已经记录的最长匹配前缀加1,否则最长匹配长度缩小到前一个匹配的最长前缀,知道匹配的最长前缀为0。后者,不一样的是拿模板字符串作为前缀进行比较,其他和第一个问题一样。

具体可查看《算法导论》,b站的一些教学视频。

实现:

代码实现示例:

  1. #include <iostream>
  2. using namespace std;
  3. int m, n;
  4. char str[] = "@bacbababaabcbab";
  5. char pattern[] = "@ababaca";
  6. int pi[10];
  7. int f[100000];
  8. void compute_next(){
  9. int j = 0;
  10. pi[1] = 0;
  11. for(int i = 2; i <= m; i++){
  12. while(j > 0 && pattern[i] != pattern[j+1]) j = pi[j];
  13. if(pattern[i] == pattern[j+1])j++;
  14. pi[i] = j;
  15. }
  16. }
  17. void compute_f(){
  18. int j = 0;
  19. for(int i = 1; i <= n; i++){
  20. while(j > 0 && str[i] != pattern[j + 1])j = pi[j];
  21. if(str[i] == pattern[j + 1])j++;
  22. f[i] = j;
  23. }
  24. }
  25. int main(){
  26. n = 15, m = 7;
  27. compute_next();
  28. compute_f();
  29. for(int i = 1; i <= n; i++){
  30. cout<<"i = "<<i<<", "<<f[i]<<endl;
  31. }
  32. return 0;
  33. }

例题: