串的匹配算法

串的匹配算法

BF算法

说明

  • BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。

  • 时间复杂度:O(mn)

示例

string s1, s2;
    cin >> s1 >> s2;
    int m = s1.size(), n = s2.size();
    int i = 0, j = 0;
    while (i < m && j < n)
    {
        if (s1[i] == s2[j])
            i++, j++;
        else
            i = i - j + 1, j = 0;
    }
    cout << (j == n ? "YES" : "NO") << endl;
KMP算法及其优化
原理和说明
  • 在匹配过程中,主串的指针不需要回溯,只回溯模式串的指针(回溯到匹配失败位置前的模式串的内容的最长公共前后缀的长度),然后继续比较
  • 优化后的KMP算法的优化点在于aaaaabaaaaacaaaaac的匹配,bc失配后与a匹配(失配),然后根据next数组,后面又是与a匹配,这里是在做无用功

前缀:包含头不包含尾的所有子串

后缀:包含尾不包含头的所有子串

最长相等前后缀:两者的交集的中的最大长度

注意:若字符串长度为1,则没有前后缀

next数组(前缀表)
void get_next(string s, int m, int ne[])
{
    ne[0] = -1;
    if (m == 1)
        return;
    ne[1] = 0;
    // i 表示要求 ne[i], cn 表示要与 s[i-1] 比对的字符的下标
    int i = 2, cn = 0;
    while (i < m)
    {
        while (cn > 0 && s[i - 1] != s[cn])
            cn = ne[cn];
        if (s[i - 1] == s[cn])
            ne[i++] = ++cn;
        else
            ne[i++] = 0;
    }
    return;
}
匹配过程
    int i = 0, j = 0;
    while (i < m && j < n)
    {
        while (j > 0 && s1[i] != s2[j])
            j = ne[j]; // 得到新的下标(>=0)
        if (s1[i] == s2[j])
            i++, j++;
        else
            i++;
    }
    cout << (j == s2.size() ? "YES\n" : "NO\n");
nextval数组
void get_nextval(string s, int m, int *ne, int *neval)
{
    neval[0] = -1;
    if (m == 1)
        return;
    int i = 0;
    while (i < m)
    {
        if (s[i] == s[ne[i]])
            neval[i] = neval[ne[i]]; // 跳过相同的匹配不上的字符
        else
            neval[i] = ne[i]; // 否则,与 next 一样
        i++;
    }
    return;
}
优化后的匹配过程
    int i = 0, j = 0;
    while (i < m && j < n)
    {
        // 如果 j == -1,说明 i 这个位置不可能匹配,所以 i++, j = 0(即j++)
        // 如果 s1[i] == s2[j], 说明 i 这个位置匹配上了,所以 i++, j++
        if (j == -1 || s1[i] == s2[j])
            i++, j++;
        else // 其他情况: j != -1 且匹配不上,则 j = neval[j]
            j = neval[j];
    }
    cout << (j == s2.size() ? "YES" : "NO") << endl;
究极完整代码
#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define int ll
#define pii pair<int, int>
#define all(x) x.begin(), x.end()

const int MOD = 1e9 + 7;
const int N = 2e5 + 2;

void get_next(string s, int m, int *ne)
{
    ne[0] = -1;
    if (m == 1)
        return;
    ne[1] = 0;

    int i = 2, cn = 0;
    while (i < m)
    {
        while (cn > 0 && s[i - 1] != s[cn])
            cn = ne[cn];
        if (s[i - 1] == s[cn])
            ne[i++] = ++cn;
        else
            ne[i++] = 0;
    }
    return;
}

void get_nextval(string s, int m, int *ne, int *neval)
{
    neval[0] = -1;
    if (m == 1)
        return;
    int i = 0;
    while (i < m)
    {
        if (s[i] == s[ne[i]])
            neval[i] = neval[ne[i]]; // 跳过相同的匹配不上的字符
        else
            neval[i] = ne[i]; // 否则,与 next 一样
        i++;
    }
    return;
}

void kmp(string s1, string s2)
{
    int m = s1.size(), n = s2.size();
    int *ne = new int[n];

    cout << "kmp匹配:\n";

    get_next(s2, n, ne);
    cout << "打印next数组:" << endl;
    for (int i = 0; i < n; i++)
        cout << ne[i] << ' ';
    cout << endl;

    int i = 0, j = 0;
    while (i < m && j < n)
    {
        while (j > 0 && s1[i] != s2[j])
            j = ne[j]; // 得到新的下标(>=0)
        if (s1[i] == s2[j])
            i++, j++;
        else
            i++;
    }
    cout << (j == s2.size() ? "YES\n" : "NO\n");
    cout << endl;
}

void kmp_plus(string s1, string s2)
{
    int m = s1.size(), n = s2.size();
    int *ne = new int[n];

    get_next(s2, n, ne);
    int *neval = new int[n];
    get_nextval(s2, s2.size(), ne, neval);

    cout << "kmp_plus匹配\n";
    cout << "打印nextval数组:" << endl;
    for (int i = 0; i < n; i++)
        cout << neval[i] << ' ';
    cout << endl;

    int i = 0, j = 0;
    while (i < m && j < n)
    {
        // 如果 j == -1,说明 i 这个位置不可能匹配,所以 i++, j = 0(即j++)
        // 如果 s1[i] == s2[j], 说明 i 这个位置匹配上了,所以 i++, j++
        if (j == -1 || s1[i] == s2[j])
            i++, j++;
        else // 其他情况: j != -1 且匹配不上,则 j = neval[j]
            j = neval[j];
    }
    cout << (j == s2.size() ? "YES" : "NO") << endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    string s1, s2;
    cin >> s1 >> s2;
    kmp(s1, s2);
    kmp_plus(s1, s2);
    return 0;
}
// 输入 
ababaaaaababaaab
ababaaab
// 输出
kmp匹配:
打印next数组:
-1 0 0 1 2 3 1 1 
YES

kmp_plus匹配
打印nextval数组:
-1 0 -1 0 -1 3 1 0 
YES

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值