前缀函数
字符串的前缀函数
概念
令字符串为s
令π[i]表示s的[0,i]区间内 真前缀s[0...k-1]和真后缀s[i-k+1...i]相等(不能重合!!!)
长度为k,若有多组,k取最大值,没有,k取0,k即为前缀函数π[i]的值
特别规定π[0]=0
例子 来源oi-wiki
举例来说,字符串 abcabcd,
π[0]=0,因为 a 没有真前缀和真后缀,根据规定为 0
π[1]=0,因为 ab 无相等的真前缀和真后缀
π[2]=0,因为 abc 无相等的真前缀和真后缀
π[3]=1,因为 abca 只有一对相等的真前缀和真后缀:a,长度为 1
π[4]=2,因为 abcab 相等的真前缀和真后缀只有 ab,长度为 2
π[5]=3,因为 abcabc 相等的真前缀和真后缀只有 abc,长度为 3
π[6]=0,因为 abcabcd 无相等的真前缀和真后缀
算法
1.朴素前缀数组计算O(n^3)
2.优化1
考虑相邻的前缀数组值最多增加1
当移动到下一个位置时,前缀函数的值要么增加一,要么维持不变,要么减少
复杂度降为O(n^2)
3.优化2
考虑如果π[i+1]可以等于π[i]+1,即s[i+1]==s[π[i]],直接转移--------------1
但是不能的话,即s[i+1]!=s[π[i]],我们就要找到仅次于π[i]的第二长度j------2
第二长度等价于s[j-1]的前缀函数值
再次比较s[i+1]和s[j],不能的话重复2
++优化的代码
vector<int> prefix_func(string s) {
int n=s.length();
vector<int> pi(n);
for(int i=1;i<n;i++) {
int j=pi[i-1];
while(j>0&&s[i]!=s[j]) j=pi[j-1];
if(s[i]==s[j]) j++;
pi[i]=j;
}
return pi;
}

浙公网安备 33010602011771号