【算法】字符串匹配算法

文章目录

  • 一、字符串匹配
    • 1. KMP
    • 2. 字符串哈希

一、字符串匹配

记:主串 s s s 长度为 m m m,子串 p p p 长度为 n n n

1. KMP

暴力的做法,是在当前字符不匹配的时候,主串和子串都回溯,这样做显然是 O ( n m ) O(nm) O(nm) 的。

K M P KMP KMP 则是主串不回溯,子串回溯到特定位置,这个特定位置由子串的 n e x t next next 数组决定。该算法的时间复杂度是 O ( n + m ) O(n + m) O(n+m)

char s[N], p[N];
int ne[N], m, n;

//下标从1开始读入字符串
cin >> n >> p + 1 >> m >> s + 1;

//求子串的next数组
for (int i = 2, j = 0; i <= n; i++)
{
    while (j > 0 && p[i] != p[j + 1]) j = ne[j];
    if (p[i] == p[j + 1]) j++;
    ne[i] = j;
}

// 匹配
for (int i = 1, j = 0; i <= m; i++)
{
    while (j > 0 && s[i] != p[j + 1]) j = ne[j];
    if (s[i] == p[j + 1]) j++;
    if (j == n)
    {
        // 匹配成功
    }
}

2. 字符串哈希

字符串哈希可以实现 O ( 1 ) O(1) O(1) 匹配子串。当然,预处理前缀哈希的过程是 O ( n ) O(n) O(n) 的。

  • 将字符串看作一个 P P P 进制数( P P P 经验值 131 131 131 )。
  • 将这个 P P P 进制数 m o d mod mod 一个较小的数(经验值 2 64 2^{64} 264),就是该字符串的哈希。

题目链接

参考代码:

#include
using namespace std;
using ull = unsigned long long;//溢出时等价mod2^64

const int N = 1e5 + 10, P = 131;
ull h[N], p[N];//h[i]存前缀哈希,p[i]存P的i次方
char s[N];//存主串

//求[l, r]子串的哈希
ull get(int l, int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}

int main()
{
    int n, m; cin >> n >> m >> s + 1;

    //预处理前缀哈希
    p[0] = 1;
    for(int i = 1; i <= n; i++)
    {
        p[i] = p[i - 1] * P;
        h[i] = h[i - 1] * P + s[i];
    }

    while(m--)
    {
        int l1, r1, l2, r2;
        cin >> l1 >> r1 >> l2 >> r2;

        if(get(l1, r1) == get(l2, r2)) cout << "Yes" << '\n';
        else cout << "No" << '\n';
    }
}

你可能感兴趣的:(算法,算法,哈希算法,数据结构)