当前位置:   article > 正文

KMP算法

KMP算法

KMP是一种字符串的匹配方法与之相同的算法还有BF(暴力解法),BM算法,Sunday算法

kmp的核心为永不回退的指针即next数组

next数组的核心为部分匹配值,对于部分匹配值我们首先要理解前缀,后缀

前缀,后缀,部分匹配值

下面以'ababa'为例进行说明:
'a' 的前缀和后缀都为空集,最长相等前后缀长度为 0.
'ab' 的前缀为{ a },后缀为{ b },{ a }^{ b } = NULL,最长相等前后缀长度为 0。
'aba' 的前缀为{ a, ab },后缀为{ a, ba },{ a, ab }^{ a, ba } = { a },最长相等前后缀长度为1。
'abab' 的前缀{ a, ab, aba }  后缀{ b, ab, bab } = { ab },最长相等前后缀长度为 2

'ababa' 的前缀{ a, ab, aba, abab }  后缀 { a, ba, aba, baba} = {a, aba},公共元素有两个,最长相等前后缀长度为 3 。
故字符串 'ababa' 的部分匹配值为 00123.

然后我们给出公式

公式

移动位数 = 已匹配的字符数 - 对应的部分匹配值(最后一个匹配成功的字符对应的匹配值)
即 move=(j-1)-next[j-1]

我们给出KMP的函数代码

  1. void get_next(char* instr, int next[], int instrlength)
  2. {
  3. int i = 0, j = -1;
  4. next[i] = -1;
  5. while (i < instrlength - 1)
  6. if (j == -1 || instr[i] == instr[j])
  7. {
  8. ++i;
  9. ++j;
  10. next[i] = j;
  11. }
  12. else
  13. j = next[j];
  14. }
  15. int Index_KMP(char* str, char* instr, int next[], int strlength, int instrlength)
  16. {
  17. int i = 0, j = 0;
  18. while (i < strlength && j < instrlength)
  19. {
  20. if (j == -1 || str[i] == instr[j])
  21. {
  22. ++i; // 继续比较后续的字符
  23. ++j;
  24. }
  25. else
  26. j = next[j]; // 模式串向后移
  27. }
  28. if (j >= instrlength)
  29. return i - instrlength;
  30. else
  31. return 0;
  32. }

下面给出完整代码 

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #define MAXSIZE 100
  5. void get_next(char* instr, int next[], int instrlength);
  6. int Index_KMP(char* str, char* instr, int next[], int strlength, int instrlength);
  7. int main()
  8. {
  9. char str[MAXSIZE];
  10. char instr[50];
  11. int strlength, instrlength;
  12. scanf("%s", str);
  13. scanf("%s", instr);
  14. instrlength = strlen(instr);
  15. strlength = strlen(str);
  16. int* next = (int*)malloc(sizeof(int) * instrlength);
  17. get_next(instr, next, instrlength);
  18. int index = Index_KMP(str, instr, next, strlength, instrlength) + 1;
  19. printf("子串在主串的位置为:%d\n", index);
  20. return 0;
  21. }
  22. void get_next(char* instr, int next[], int instrlength)
  23. {
  24. int i = 0, j = -1;
  25. next[i] = -1;
  26. while (i < instrlength - 1)
  27. if (j == -1 || instr[i] == instr[j])
  28. {
  29. ++i;
  30. ++j;
  31. next[i] = j;
  32. }
  33. else
  34. j = next[j];
  35. }
  36. int Index_KMP(char* str, char* instr, int next[], int strlength, int instrlength)
  37. {
  38. int i = 0, j = 0;
  39. while (i < strlength && j < instrlength)
  40. {
  41. if (j == -1 || str[i] == instr[j])
  42. {
  43. ++i;
  44. ++j;
  45. }
  46. else
  47. j = next[j];
  48. }
  49. if (j >= instrlength)
  50. return i - instrlength;
  51. else
  52. return 0;
  53. }

我们在以LeetCode第28题为例

在此题中查找主串中的子串的下标我们可以用KMP算法解决

我们先找到next数组

  1. for (int i = 1, j = 0; i < m; i++) {
  2. while (j > 0 && needle[i] != needle[j]) {
  3. j = next[j - 1];
  4. }
  5. if (needle[i] == needle[j]) {
  6. j++;
  7. }
  8. next[i] = j;
  9. }

 这里我们只需要记住模板就行因为原理上文已经讲过了,这里只是实现

之后我们在开始匹配

  1. for (int i = 0, j = 0; i < n; i++) {
  2. while (j > 0 && haystack[i] != needle[j]) {
  3. j = next[j - 1];
  4. }
  5. if (haystack[i] == needle[j]) {
  6. j++;
  7. }
  8. if (j == m) {
  9. return i - m + 1;
  10. }
  11. }
  12. return -1;

下面给出完整代码

  1. int strStr(char * haystack, char * needle){
  2. int n = strlen(haystack), m = strlen(needle);
  3. if (m == 0) {
  4. return 0;
  5. }
  6. int next[m];
  7. next[0] = 0;
  8. for (int i = 1, j = 0; i < m; i++) {
  9. while (j > 0 && needle[i] != needle[j]) {
  10. j = next[j - 1];
  11. }
  12. if (needle[i] == needle[j]) {
  13. j++;
  14. }
  15. next[i] = j;
  16. }
  17. for (int i = 0, j = 0; i < n; i++) {
  18. while (j > 0 && haystack[i] != needle[j]) {
  19. j = next[j - 1];
  20. }
  21. if (haystack[i] == needle[j]) {
  22. j++;
  23. }
  24. if (j == m) {
  25. return i - m + 1;
  26. }
  27. }
  28. return -1;
  29. }

总结

KMP算法是一种时间复杂度为O(m+n)的一种字符串匹配算法,属于简单算法的一种核心为永不回退的指针j,以及next数组,以后我们还会学习BM算法以及Sunday算法

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/182875
推荐阅读
相关标签
  

闽ICP备14008679号