文章目录
- 一、字符串匹配
- 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<bits/stdc++.h>
using namespace std;
using ull = unsigned long long;//溢出时等价mod2^64const 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';}
}