算法训练day9|| 28.找出字符串中第一个匹配项的下标(kmp算法)

发布于:2022-12-04 ⋅ 阅读:(588) ⋅ 点赞:(0)

kmp算法可以解决什么问题?

可以解决字符串中文本串和模式串之间的匹配问题(降低时间复杂度)。

kmp数组里面的next数组是什么?前缀表是什么?

next数组是前缀表,前缀表(也就是next数组)中每个索引位置的值都是该位置的最长相同前缀后缀数,什么是前缀后缀?前缀是以第一个元素为起始不包含最后一个元素的连续串,后缀是包含最后一个元素不包含第一个元素的连续串。

为什么使用前缀表不使用其他表?

因为前缀表中记录了模式串中每个元素的最长相同前缀后缀的长度,每次在匹配文本串和模式串时遇到不相同的情况时,如果有前缀表的话可以不从头开始匹配,而是根据前缀表对应的值返回上到特定的地方进行匹配。

解题思路:

先构建一个前缀表(next数组),然后匹配模式串和文本串的时候使用next数组。我觉得难点在于题解给的构造next数组。

构造next数组的步骤:

1.进行初始化:初始双指针i,j。i初始化next数组的后缀的末尾,j初始化为next数组的前缀的末尾,j还是最长相等前缀后缀数。

2.两指针对应的字符不同的情况。

3.两指针对应字符相同的情况。

4.更新next

构建next的代码部分:

 void getNext(int *next,string &a){
         //不能传入数组的引用对数组进行操作,只能传入指向数组的地址对数组进行操作
    int i,j=0;
    next[0]=0;
    //i代表后缀的末尾,j代表前缀的末尾,并且j是最大相等前缀后缀数。
    for(int i=1;i<a.size();i++){
         while(j>0&&a[i]!=a[j]){
        j=next[j-1];//如果不相等就跳转,j的就跳转到next[j-1]
    }
    if(a[i]==a[j]){
        j++;
    }
    next[i]=j;
    }
   
 }

 注意点:当a[i]!=a[j]这里的判断是while而不是if,例如aabaaf,当匹配到f的时候,f的最长前缀后缀相等于就有三种可能,3和2和1,如果使用if的话,只判断了他是否是3的情况。

对于这个题解我的困惑:

这个题解,我不清楚是怎么想到这样的一个方法的,虽然我觉得这个方法很妙,但是我可以也可以用代码写出一个构建next数组的方法,只不过时间复杂度是o(n^2),所以我暂且认为写出这样的算法是因为作者的算法能力很强,在尝试过程中写出的。所以我暂时先背下来这个构造next数组的方法(怎么记呢?就是模仿匹配操作,当i,j对应字符不相同时,j=next[j-1],当相同时j++)。以后再看到再试试理解他是如何想出的。

整体题解代码:

class Solution {
public:
     void getNext(int *next,string &a){
         //不能传入数组的引用对数组进行操作,只能传入指向数组的地址对数组进行操作
    int i,j=0;
    next[0]=0;
    //i代表后缀的末尾,j代表前缀的末尾,并且j是最大相等前缀后缀数。
    for(int i=1;i<a.size();i++){
         while(j>0&&a[i]!=a[j]){
        j=next[j-1];//如果不相等就跳转,j的就跳转到next[j-1]
    }
    if(a[i]==a[j]){
        j++;
    }
    next[i]=j;
    }
   
 }
 int strStr(string haystack, string needle) {
        if (needle.size() == 0) {
            return 0;
        }
        int next[needle.size()];
        getNext(next, needle);
       //得到前缀表next,我们可以进行文本串与模板串比较的问题了
        //使用两个指针i,j。i指向文本串起始位置,j指向模板串起始位置
        int i,j=0;
        //如果h[i]==n[j];j++.
        //如果不相等j=next[j-1];然后继续进行比较
         for (int i = 0; i < haystack.size(); i++) {
            while(j > 0 && haystack[i] != needle[j]) {
                j = next[j - 1];
            }
            if (haystack[i] == needle[j]) {
                j++;
            }
            if (j == needle.size() ) {
                return (i - needle.size() + 1);
            }
        }
        return -1;
    }
};


网站公告

今日签到

点亮在社区的每一天
去签到