字符串匹配问题(BF,KMP)

x33g5p2x  于2021-10-04 转载在 其他  
字(2.5k)|赞(0)|评价(0)|浏览(341)

BF算法

BF的全称为Brute Force,所以BF算法又叫做暴力算法。下面我们来看看BF算法解决字符串匹配问题的一个例子,相信看完之后,BF算法解决此问题中的难点你就明白了。

其实BF算法解决字符串匹配问题是很简单的,比较让人难以理解的就是他的返回值i-j+1和为什么最后打印i-j,在图中已经将此问题说的很清楚了。

代码实现

  1. #include<iostream>
  2. #include<assert.h>
  3. #include<string.h>
  4. using namespace std;
  5. int BF(char* str, char *sub) //str表示主串,sub表示子串
  6. {
  7. assert(str != NULL&&sub != NULL);
  8. int lenstr = strlen(str);
  9. int lensub = strlen(sub);
  10. int i = 0, j = 0;
  11. while (i < lenstr&&j < lensub)
  12. {
  13. if (str[i] == sub[j])
  14. {
  15. i++;
  16. j++;
  17. }
  18. else
  19. {
  20. i = i - j + 1; //表示匹配不成功后i要返回的位置,不懂的可以看下面的图
  21. j = 0; //j则返回到起始位置
  22. }
  23. }
  24. if (j >= lensub) //此时说明匹配成功
  25. {
  26. return i - j; //返回匹配成功的起始下标
  27. }
  28. return -1; //没有匹配成功
  29. }
  30. int main()
  31. {
  32. printf("%d\n", BF("ababababcd", "abcd")); //6
  33. printf("%d\n", BF("ababababcd", "abcdf")); //-1
  34. printf("%d\n", BF("ababababcd", "ab"));//0
  35. return 0;
  36. }

时间复杂度:O(M/*N) M和N分别为主串和子串的长度。

我们发现如果数据量一大,那么这个算法十分的低效,那有没有更加高效的算法了?当然是有的,下面我们来看看KMP算法。

KMP算法

这儿我们主要讲解KMP算法最核心也是最主要的部分,next数组的如何形成。 至于KMP算法的基础部分B站或者博客上有许多对它的讲解,这儿博主就不在讲解了,不懂的小伙伴可以去网上自己学习下。

核心创建next数组

  1. void Creatnext(char* sub, int *next, int lensub)
  2. {
  3. next[0] = -1;
  4. next[1] = 0;
  5. int i = 2;
  6. int k = 0;
  7. while (i < lensub)
  8. {
  9. if (k == -1 || sub[i - 1] == sub[k])
  10. {
  11. next[i] = k+1;
  12. i++;
  13. k++;
  14. }
  15. else
  16. {
  17. k = next[k];
  18. }
  19. }
  20. }

注意:
1.这里我们是从头开始求的,并不知道next[2]等于什么,所以我们要利用此时的条件,我们知道了next[1]为多少,也就是i的前一个next是多少,所以只要有sub[i-1]=sub[k],我们就可以退出next[i]=k+1。这个很抽象,最好要结合画图去理解。
2.记录完一个位置的next之后,就要i去记录下一个位置的next,k也要,因为这个时候你回退的位置也发生了变化,而且有个规律,k每次增加最多只能增加1,但是减少就不一定了。
3.k==-1要处理下,这时说明回退到-1这个位置都没有找到一样的,之后仍然要进行if括号里面的代码。
4.k=next[k],表示回退时的位置与sub[i-1]不一样就一直回退,直到回退到k==-1。

剩余的代码部分其实和BF算法差不多。下面来看看完整的代码。

完整代码

  1. #include<iostream>
  2. #include<assert.h>
  3. #include<stdlib.h>
  4. #include<string.h>
  5. using namespace std;
  6. void Creatnext(char* sub, int *next, int lensub)
  7. {
  8. next[0] = -1;
  9. next[1] = 0;
  10. int i = 2;
  11. int k = 0;
  12. while (i < lensub)
  13. {
  14. if (k == -1 || sub[i - 1] == sub[k])
  15. {
  16. next[i] = k+1;
  17. i++;
  18. k++;
  19. }
  20. else
  21. {
  22. k = next[k];
  23. }
  24. }
  25. }
  26. int KMP(char* str, char* sub)
  27. {
  28. assert(str != NULL&&sub != NULL);
  29. int lenstr = strlen(str);
  30. int lensub = strlen(sub);
  31. /*if (pos<0 || pos>lenstr) { return -1; }*/
  32. int* next = (int *)malloc(sizeof(int)*lensub);
  33. if (next == NULL)
  34. {
  35. printf("malloc failed\n");
  36. exit(-1);
  37. }
  38. Creatnext(sub, next, lensub);
  39. int i = 0;
  40. int j = 0;
  41. while (i<lenstr&&j<lensub)
  42. {
  43. if (j==-1||str[i] == sub[j])
  44. {
  45. i++;
  46. j++;
  47. }
  48. else
  49. {
  50. j = next[j];
  51. }
  52. }
  53. if (j >= lensub)
  54. {
  55. return i - j;
  56. }
  57. return -1;
  58. }
  59. int main()
  60. {
  61. printf("%d\n", KMP("ababababcd", "abcd")); //6
  62. printf("%d\n", KMP("ababababcd", "abcdf")); //-1
  63. printf("%d\n", KMP("ababababcd", "ab"));//0
  64. return 0;
  65. }

这篇文章知识博主目前对KMP算法的浅薄认识,相信随着日后的学习,一定会对它有更深刻的理解。日后如果有什么所想,也会添加到此文章中。

相关文章