给定两个字符串 a
和 b
,寻找重复叠加字符串 a
的最小次数,使得字符串 b
成为叠加后的字符串 a
的子串,如果不存在则返回 -1
。
注意:字符串 "abc"
重复叠加 0 次是 ""
,重复叠加 1 次是 "abc"
,重复叠加 2 次是 "abcabc"
。
示例 1:
输入:a = "abcd", b = "cdabcdab" 输出:3 解释:a 重复叠加三遍后为 "abcdabcdabcd", 此时 b 是其子串。
class Solution {
//字符串匹配算法--Rabinkarp(哈希)
public static int repeatedStringMatch(String a, String b) {
int x=is(a,b);
if(x==-1) return -1;
if(a.length()-x>=b.length()) return 1;
return (x+b.length()-1-a.length())/a.length()+2;
}
private static int is(String a, String b) {
int n=a.length(),m=b.length();
int x=31;//x进制
int y=10000007;//哈希值对y取模,以防溢出
//第一步先将待匹配字符串(b)的哈希值求出
long hashb=0;//记录b的哈希值
for (int i = 0; i <m ; i++) {
hashb=(hashb*x+b.charAt(i))%y;//先进位再相加,后对hashb取模
}
//第二步,将a中从头到尾的每一个元素都作为首元素,取b.length个数,求得哈希值做比较
long hasha=0;//记录a的m个数的哈希值
long t=1;//记录hasha中第一个数的哈希值,以便后续进行滑动窗口操作,避免重复计算
for (int i = 0; i <m-1 ; i++) {//先求得前(m-1)个数的哈希值
hasha=((hasha*x)+a.charAt(i%n))%y;//i%n相当于对a无限复制扩大
t=(t*x)%y;
}
for (int i = m-1; i <n+m-1 ; i++) {//i表示末尾元素,最后一项将a中末尾元素当做首元素,所以n+m-1
hasha=((hasha*x)+a.charAt(i%n))%y;
if(hasha==hashb) return i-m+1;//返回首元素
hasha=(hasha-a.charAt((i-m+1)%n)*t)%y;//未匹配成功,删除首元素的哈希值
hasha=(hasha+y)%y;
}
return -1;//未能成功匹配
}
}