Posted onInacm
,
字符串 Symbols count in article: 542Reading time ≈1 mins.
z函数(扩展kmp)
对于一个长度为 n 的字符串 s,定义函数 z[i] 表示 s 和 s[i,n-1](即以s[i] 开头的后缀) 的最长公共前缀(LCP) ,则 z 被称为 s 的 z 函数。特别的,z[0] = 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14
vector<int> z_function(string s){ int n = (int)s.length(); vector<int> z(n); for (int i = 1, l = 0, r = 0; i < n; ++i) { if (i <= r && z[i - l] < r - i + 1) { z[i] = z[i - l]; } else { z[i] = max(0, r - i + 1); while (i + z[i] < n && s[z[i]] == s[i + z[i]]) ++z[i]; } if (i + z[i] - 1 > r) l = i, r = i + z[i] - 1; } return z; }
字符串整周期
给定一个长度为 n 的字符串 ,找到其最短的整周期,即寻找一个最短的字符串 t ,使得 s 可以被若干个 t 拼接而成的字符串表示。
考虑计算 s 的 Z 函数,则其整周期的长度为最小的 n 的因数 i ,满足 i + z[i] = n。
#include<bits/stdc++.h> usingnamespace std; #define ull unsigned long long constint maxn = 1e5 + 10; char a[maxn];//文本串 char b[maxn];//模式串 int kmp_next[maxn];
voidget_next(int m) { int j = 0; kmp_next[0] = 0;//初始化 for (int i = 1; i <= m;++i) { //当这一位不匹配时,将j指向此为之前最大公共前后缀的位置 while(j>0&&b[i]!=b[j]) j = kmp_next[j-1]; if (b[i] == b[j])//如果这一位匹配,那么将j+1,继续判断下一位 ++j; kmp_next[i] = j; } }
//找到b在a中第一次出现的位置 intfind_pos(int n,int m) { int i, j = 0; int p = -1; get_next(m); for (i = 0; i < n;++i) { while(j>0&&a[i]!=b[j]) j=kmp_next[j-1]; if (a[i] == b[j]) ++j; if (j == m) { p = i - m + 1; break; } } //返回位置p的值 return p; }
//找到b在a中第k次出现的位置 intfind_num(int n,int m,int k) { int i, j = 0; int res = 0; get_next(m); for (i = 0; i < n;++i) { while(j>0&&a[i]!=b[j]) j=kmp_next[j-1]; if (a[i] == b[j]) ++j; if (j == m) ++res; } //返回数量 return res; }