基础 kmp
KMP算法用于在线性时间复杂度内寻找字符串中是否含有某个子串的情况
本质上是通过移动待查询子串的相对位置来寻找是否有该子串, 移动的方式则通过Next数组来记录
Next数组中记录的是最大相同前后缀的长度
视频: 最浅显易懂的 KMP 算法讲解_哔哩哔哩_bilibili
KMP寻找所有匹配区间
int f[N + 10];
//预处理
void getfill(string s) {
memset(f, 0, sizeof(f));
for (int i = 1; i < s.length(); i++){
int j = f[i];
while (j && s[i] != s[j])
j = f[j];
f[i + 1] = (s[i] == s[j]) ? j + 1 : 0;
}
}
//记录所有匹配区间 [指在长串中的下标,下标从0开始]
struct Interval{
int l, r;
}q[N];
//记录匹配次数
int t;
//找到并记录所有的匹配区间, a长 s短
void findinterval(string a, string s){
getfill(s);
int j = 0;
t = 0;
for (int i = 0; i < a.length(); ++i){
while (j && a[i] != s[j])
j = f[j];
if (a[i] == s[j])
j++;
if (j == s.length()){
t++;
q[t].l = i - s.length() + 1;
q[t].r = i;
}
}
}
拓展 kmp (待补充)
字符串哈希
通过一个哈希值来表示整个字符串的方法
求哈希值需要两个素数 base 和 mod , 一般 base < mod , 尽量取大
一般 base == 131 , mod == 19260817 或 1e9+7 即可
对一段标记为 s == x1x2x3...xn 的字符串, 有如下公式
单哈希公式
其中 F(s[i]) 表示字符串中第 i 个字符所映射到的数值, 例如 'a' 映射到 1 , 'z' 映射到 26
求某段子串的哈希值
base 幂的地方一般先预处理一遍
实例代码如下
ll base = 131;
ll mod = 1e11+7;
ll has[N];
ll p[N];
void init()
{
p[0] = 1;
for (ll i = 1; i < N; i++)
{
p[i] = p[i - 1] * base;
}
}
ll hashs(string s)
{
has[0] = 0;
for (ll i = 0; i < s.length(); i++) //配合string的下标表示
{
has[i+1] = (has[i] * base + (s[i] - 'a' + 1)) % mod;
}
return has[s.length()];
}
ll gethas(ll l, ll r)
{
return ((has[r] - has[l - 1] * p[r - l + 1]) % mod + mod) % mod;
}
二维哈希
与双哈希并非一个意思, 双哈希用于进一步降低哈希冲突的概率, 而二维哈希是用于解决矩阵性质的问题
原理与一维哈希类似, 通过先对每一行横向求哈希值, 在此哈希表的基础上再对每一列纵向求哈希值, 由此得到一个哈希阵列, 因此二维哈希需要两个base, 也同样需要两次预处理
二维哈希公式
求子矩阵 (a, b) * (x, y) 的哈希值 (a <= x, b <= y)
实例代码如下
ll hashs(ll x, ll y)
{
has[0][0] = 0;
for(ll i = 1; i<N;i++)
{
has[0][i] = 0;
has[i][0] = 0;
}
for (ll i = 1; i <= x; i++)
{
for (ll j = 1; j <= y; j++)
{
has[i][j] = (has[i][j - 1] * base1 + (M[i][j] - 'a' + 1));
}
}
for (ll j = 1; j <= y; j++)
{
for (ll i = 1; i <= x; i++)
{
has[i][j] = (has[i - 1][j] * base2 + has[i][j]);
}
}
return has[x][y];
}
ll gethas(ll a, ll b, ll x, ll y)
{
return has[x][y] - has[x][b - 1] * p1[y - b + 1] - has[a - 1][y] * p2[x - a + 1] + has[a - 1][b - 1] * p1[y - b + 1] * p2[x - a + 1];
}