Next数组求法
不用初始化,因为Next数组是递推出来的。用法为getFail(s,strlen(s)).
const int MAX_N=101000;
char str[MAX_N],pattern[MAX_N];
int Next[MAX_N];
void getFail(char *p,int plen){
int i;
Next[0]=0;Next[1]=0;
for(i=1;i<plen;i++){
int j=Next[i];
while(j&&p[i]!=p[j])
j=Next[j];
Next[i+1]=(p[i]==p[j])?j+1:0;
}
}
囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖
学习笔记
KMP的Next数组可以求一个字符串的最小循环节,如果它有的话。
循环节长度 x=len-Next[len]。
比如ababab,x为2
abbcabbcabbc,x为3
但是如果是abba的话x为3,如果想要求这个字符串的最小循环节长度再加一个判断条件即可,
即如果len%x!=0的话x=len。
像abba,x应该为len,即为4.
像abbabba,x应该为7,abbabbab,x为8,abbabbabb,x为3,因为它可以整除了。
另一个问题,如果一个字符串,我最少需要添加多少个字符才可以出现2个及以上的循环。
添加字符之后的字符串的最小循环节长度为len-Next[len]。
那么答案即为(len-Next[len])-len%(len-Next[len])。
可以看成(循环节)-字符串长度%(循环节)。
定理:如果一个字符串有循环节的话且循环节且总长度可以整除循环节,即没有末尾循环节破损,那么最小循环节长度为len-Next[len],如果循环节破损,那么在没法添加字符的条件下最小循环节长度即为字符串本身长度len,而在可以添加字符的条件下,如果想要添加字符串数量最少,那么添加完之后字符串的最小循环节为len-Next[len]。
囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖囖
利用Next数组求字符串的前缀在字符串中出现的次数。
利用dp,dp[i]代表字符串的第1个字符到第i个字符这个子串出现在字符串中的次数(字符串下标从1开始,方便),这个出现次数是可重复的,比如aaaaa的dp[2]为4。
dp数组求法
int len=strlen(s);
getFail(s,len);
for(i=1;i<=len;i++)
dp[i]=1;
for(i=len;i>=1;i--)
dp[Next[i]]+=dp[i];
小思维:
求字符串a的每个前缀在b中出现的次数。
可以把构建一个字符串c=a+’#’+b,然后求出dp_c,然后再求出dp_a,那么答案就为dp_c[i]-dp_a[i]。