[KMP算法]字符串匹配

KMP算法(字符串匹配)


 

适用问题举例:

给定两个字符串,问:模式串是否在主串中出现过。 如果出现过,输出模式串在主串中首次出现的位置。 如果没出现过,输出-1。

暴力算法:时间复杂度为O(m*n)

1、先将模式串的第一个字符与主串的第一个字符对齐。

2、从对齐位置开始对每个字符进行逐一匹配。

3、若单个字符匹配成功,则继续比对。

4、若单个字符匹配失败,则把模式串向右移动一个单位。

int find(char p[], char t[])
{
    int m = strlen(p);//strlen用于获得char数组的长度
    int n = strlen(t);//m为模式串长度,n为主串长度
    int j = 0, i = 0;//i是主串中此时在比对的位置,j是模式串的位置
    while (i < n && j < m)
    {
        if (t[i] == p[j])
            i++, j++;//比对成功,进行下个字符的比对
        else
        {
            i -= j - 1;
            j = 0;
        }
        if (j == m)return i - j;//比对成功
    }
    return -1;//比对失败返回-1
}

KMP算法解法:

先给代码,一团雾水然后往下看hh。

void init(char p[])
{
    Next[0] = -1;
    int i = 0, j = -1;
    int m = strlen(p);
    while (i < m)
    {
        if (j == -1 || p[i] == p[j])
            Next[++i] = ++j;
        else j = Next[j];
    }
}
int find(char p[], char t[])
{
    int m = strlen(p),n = strlen(t),j = 0, i = 0;
    while (i < n && j < m)//逐位比对
    {
        if (j == -1 || t[i] == p[j])//比对成功
            i++,j++;
        else j = Next[j];//i不变,j回退
        if (j == m) return i - j;//匹配成功
    }
    return -1;
}

构建Next数组:

不难发现,我们在构建计算Next数组时只用到了模式串而不需要主串的数组。

对于每个模式串都有确定的Next数组。例如:

下标 0 1 2 3 4 5 6 7 8 9
模式串 A B C D A B C E F G
Next[] -1 0 0 0 0 1 2 3 0 0

他的目标是实现快速比对,可以有效减少匹配的次数。

当然Next表求出来不止适用于KMP算法,遇到很多字符串匹配查找的问题都可以想一想用这个

简短代码:(时间复杂度O(m+n))

int n = strlen(t + 1), m = strlen(p + 1);
//先求出匹配串的next数组
for (int i = 2, j = 0;i <= m;i++) {
    while (j && p[j + 1] != p[i])j = Next[j];
    if (p[j + 1] == p[i])j++;
    Next[i] = j;
}
 //再用得到的next 去匹配s
 for (int i = 1, j = 0;i <= n;i++) {
    while (j && p[j + 1] != t[i])j = Next[j];
    if (p[j + 1] == t[i])j++;
    if (j == m) {//匹配成功
        cout << i - m + 1 << endl;
        j = Next[j];
    }
}

 

简短版的代码是CST的一个学长写的,看不明白的不要勉强自己,看懂上面那个就行了,KMP本身就不是一个好理解的算法orz


 

制作:BDT20040

posted @ 2021-09-12 23:01  流白李  阅读(101)  评论(0编辑  收藏  举报