• 串的匹配 (KPM算法)


    前言:

    引入 KPM 算法的前提是 , B-F算法中,匹配失败后不必完全从头再来 , 找到可以利用的信息 , 可以进行跳跃性匹配

    下面 , 我们对字符串匹配的一些思路进行剖析:

    开始匹配的操作 ,我们会让 目标串 s , 和 模式串进行对齐,就像如图所示:

    e55678958f6e4c9a99c0f57ca549f469.png


     我们当然是从串 t 的头结点开始对比 

    0194aac473d04c78965142bbe0f92031.png

       对比 第一个元素 , 符合


    dfb2d1a5096a41d7a7ca14163a29b810.png

    然后对比第二个 元素符合


    3f744375a9464670baa336dd1f49c60c.png

     对比第三个元素 , 不相等


    此时 , 按照我们 B-F算法 , 不相等 , 我们就需要重新从 串 s 的第二个元素, 进行和 串 t 进行比较了  

    如图 : 

    ce7e713e54524aa7a8979c68c4bac560.png

    但是 , 此时我们注意到 , 我们开头已经对比了 串 t 和 串 s 两个元素重合 , 并且他们互不相等 , 说明再次把串 t 的开头 和  串 s 的第二个元素是不明智的选择

    因为 , 我们既然要寻找和串 t 相等的串 , 首先要保证的就是 , 串 t 的头结点要和串 s 元素先匹配上, 然后我们才能继续后续的对比 

    我们现在前两个节点已经重合, 并且他们互不相同 , 就没必要再移动一位了重合比较了

    所以 , 我们直接 将串 t 开头和 串 s 的第三个元素进行比较即可

    e74fd960d1a4443689b5b29d0399741d.png


    我们接着对比 , a 相等 , b 相等 , c 相等 , a 相等 , 当比较到串 t 的第五个元素时 , b 和 c 不相等 ,

    此时, 我们如果还采取 B-F算法当然也是可以的 , 逐个将 串t 和 对比初始位置后移的串 s 进行对比 ,

    edeea621f2f24a4c875eca92cd12b3a1.jpeg

     ccefb8f913a14ee09ea24581236e4aa5.png

    922a63afa5524188a61194a387303453.png


    我想 , 上面的步骤有些是没必要的 , 因为我们此时分析 :

    9469781c1c0a4bf09b61116d3ad223e3.png

    串 t 此时我们已经对比了五个元素 , 前 四个已经对比符合了 ,

    我们现在第五个元素, 对比到了不同元素 , 我们能直接把对比过的字符串抛弃吗? 

    意思就是说 , 我们能下定论, 已经对比过的字符, 不会再有可以匹配的子串了呢?

    能直接如下图所示吗? 

    聪明的我们, 会发现 , 我们就算对比重合过的字符 , 遇到不同的字符 , 我们也不能直接把 比较重合过的字符全部抛弃 , 除非对比过的字符互不相同 , 那 我们直接略过也没事 , 

    但是如果, 我们对比过的字符 , 有和 串 t 头结点相等的节点 , 我们就不能略过了 

    上图, 标蓝 部分 , 我们在我们在对比的时候已经对比过了 , 我们会发现  串 t 里面有两个头节点 , 那当我对比到 第二个头结点之后的一个节点的时候 , 我们如果发现不同字符 , 我们就可以把第二个头结点当作头结点, 然后后续接着让 串 t 的第二个节点和 串 s 进行比较


    我们上面的意思就是 , 假如现在有一个

    e16e24aa04494820bf5469c9349f89aa.png

    当串 s 和 串 t 元素进行比较时 , 当一个字符不匹配的时候 , 我们必然要让 串 t 开头 往后移动

    但是逐个比较的话 , 有些节点是没必要比较的 , 如下图:

    明明知道, 前五个字符两个串对比符合了, 并且五个字符互不相同 , 就没必要逐个错峰比较了,

    直接跳过这五个元素 , 让 串 t 第一个元素和串 s 第五个元素进行比较

    但是 , 有的情况 , 当比较到不同字符时 , 那个字符前面有和头结点相同的子串的话 ,我们就可以直接把 头结点子串的位置, 拉到 不同字符前面的头节点子串的位置 , 这样就不会错过重合的机会了.

    如下图

    bd08cbe32a724895b6e694ec0e6c8b24.png

    经过上面的分析 , 我们得出, 如果要准确把握模式串 t 每个字符 比较到不同的字符的时候 ,应该跳到串 t 哪个字符再和 串 s那个元素进行比较 , 就需要找出每个字符前面的和头结点子串相等的子串 , 

    那当子串有很多呢 ? 找哪一个呢?

    我们就需要引入前缀串和后缀串 

    作者能力有限 , 下一篇博客 ,转载大佬解析 ,我这里只做思路引导 . 

    c代码:

    1. #include
    2. #include "sqString.h"
    3. void GetNext(SqString t , int next[])
    4. {
    5. int j,k;
    6. j = 0;
    7. k = -1;
    8. next[0] = -1;
    9. while(j-1)
    10. {
    11. if(k == -1 || t.data[j] ==t.data[k])
    12. {
    13. j++;
    14. k++;
    15. next[j] = k;
    16. }
    17. else
    18. {
    19. k = next[k] ;
    20. }
    21. }
    22. }
    23. //进行验证
    24. int KMPIndex(SqString s, SqString t)
    25. {
    26. int next[MaxSize],i=0,j=0;
    27. GetNext(t,next);
    28. while(i
    29. {
    30. if(j == -1 || s.data[i] == t.data[j])
    31. {
    32. i++;
    33. j++;
    34. }
    35. else
    36. {
    37. j = next[j];
    38. }
    39. }
    40. if(j >= t.length)
    41. {
    42. return(i - t.length);
    43. }
    44. else
    45. {
    46. return(-1);
    47. }
    48. }
    49. int main()
    50. {
    51. SqString s,t;
    52. StrAssign(s,"ababcabcacbab");
    53. StrAssign(t,"abcac");
    54. printf("s:");
    55. DispStr(s);
    56. printf("t:");
    57. DispStr(t);
    58. printf("位置: %d\n",KPMIndex(s.t));
    59. return 0;
    60. }

  • 相关阅读:
    【全网最详细】最全java面试题及答案(210道)
    JSP request对象功能详解说明
    【JVM基础】程序计数器
    Java IO:RandomAccessFile简介说明
    强化学习代码实战(3) --- 寻找真我
    第4周 一步步搭建多层神经网络以及应用(1 & 2)
    nodejs安装和环境配置-Linux
    Vue开发实例(六)实现左侧菜单导航
    aarch64 arm64 部署 stable diffusion webui 笔记 【2】继续安装其他依赖 gfpgan
    _cpp AVL树(map、set等关联式容器的底层结构)
  • 原文地址:https://blog.csdn.net/qq_57484399/article/details/127553756