leetcode 28 459 总结 KMP算法

发布时间 2023-07-21 02:47:17作者: LiviaYu

28

解法一,暴力法

//暴力
        if(haystack.length()<needle.length())
        {
            return -1;
        }
        for(int i=0;i<=haystack.length()-needle.length();i++)
        {
            if(needle==haystack.substr(i,needle.length()))
            {
                return i;
            }
        }
        return -1;

KMP算法

暴力算法的不足:每次都从第二串的头部开始匹配,没有从上一次的匹配中收获有用信息
KMP算法核心:利用匹配失败后的信息,尽量减少模式串和主串的匹配次数,达到快速匹配的目的 主串:A 模式串:B
KMP算法不回溯i,只回溯j到指定位置
只有当A子串的后缀集合与B子串的前缀集合有交集时,回溯j

B串需要往后移动多少即j回溯的位置,所以需要找到B子串前缀集合与A子串的后缀集合的交集中最长元素,最长元素使B串后移最少,已知匹配的最多,所以需要其长度
因为在前面的匹配中,B子串=A子串,所以上述可以表示为,B子串的前缀集合和他本身的后缀集合的交集,

j指针的位置=B字串的最长公共前后缀
通过隐藏信息,匹配失败时,A串和B串存在着一段相同的子串,j指针的位置,只与B串有关,与A无关,
所以,可以在匹配之前就通过B串计算回溯位置,存在一个数组next当中,
next与B串形成映射数组,next[i]就是B[1]~B[i]的最长公共前后缀的长度

具体的匹配步骤
i,j初始化为0

  1. 如果A[i]=B[j],i++,j++继续匹配
  2. 如果A[i]!=B[j],回溯j到next[j],直到A[i]B[j],
    当j=0时,忽略j,增加i,知道A[i]
    B[j]
    3.当j=模式串长度,输出位置,继续匹配

只能说不是很理解

int n=haystack.length();
        int m=needle.length();
        //计算next数组
        vector<int> pi(m);
        for (int i = 1, j = 0; i < m; i++) {
            while (j > 0 && needle[i] != needle[j]) {
                j = pi[j - 1];
            }
            if (needle[i] == needle[j]) {
                j++;
            }
            pi[i] = j;
        }

        //匹配
        for(int i=0,j=0;i<n;i++)
        {
            while(j>0&&haystack[i]!=needle[j])
            {
                j=pi[j-1];
            }
            if(haystack[i]==needle[j])
            {
                j++;
            }
            if(j==m)
            {
                return i-j+1;
            }
            

        }
        return -1;