描述
给定一个仅由小写字母组成的长度不超过1e6的字符串,将首字母移动到末尾并记录所得的字符串,不断重复操作,虽然记录了无限个字符串,但其中不同的字符串数目是有限的,问不同的字符串有多少个?
输入:
abab
输出
2
解释:记录了 abab 和 baba两个不同的字符串
思路:
用到的思想:Kmp求最小循环节
KMP最小循环节、循环周期:
定理:假设S的长度为len,则S存在最小循环节,循环节的长度L为len-next[len],子串为S[0…len-next[len]-1]。
(1)如果len可以被len - next[len]整除,则表明字符串S可以完全由循环节循环组成,循环周期T=len/L。
(2)如果不能,说明还需要再添加几个字母才能补全。需要补的个数是循环个数L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]。
参考:https://blog.csdn.net/qq_36561697/article/details/81844145
如果字符串中有循环的话,那么循环的部分是通过上面的操作不可能得到和原来不同的字符串的。于是问题转化为求字符串中的循环节。假设字符串长度了n,利用kmp的next数组求出的循环节长度为Next[n],那么我们去掉循环部分得到的答案为 len,这里还需要注意的是党 n%len == 0的时候 答案是 len ,否则答案是 n。比如 aabbaaa 这个样例 答案是 7
-
实现:
public class countStrDemo {
private int[] getnext(String str){
int[] next=new int[str.length()];
int i=0,j=-1;
next[0]=-1;
while(i<str.length()-1){
if(j==-1||str.charAt(i)==str.charAt(j)){
i++;
j++;
next[i]=j;
}else{
j=next[j];//若字符值不相等,则j值回溯
}
}
return next;
}
public static void main(String[] args) {
countStrDemo csd=new countStrDemo();
String str="abdabdab";
String str2="abcabcd";
int[] next=csd.getnext(str2);
int n=str2.length();
int x=next[str2.length()-1]+1;//循环部分的长度
int len=n-x;//最小循环节,去掉循环部分的长度
if(n%len==0){
System.out.println(len);
}else{
System.out.println(n);
}
}
}