给定两个字符串 a 和 b,寻找重复叠加字符串 a 的最小次数,使得字符串 b 成为叠加后的字符串 a 的子串,如果不存在则返回 -1。
注意:字符串 “abc” 重复叠加 0 次是 “”,重复叠加 1 次是 “abc”,重复叠加 2 次是 “abcabc”。
示例 1:
输入:a = “abcd”, b = “cdabcdab”
输出:3
解释:a 重复叠加三遍后为 “abcdabcdabcd”, 此时 b 是其子串。
示例 2:
输入:a = “a”, b = “aa”
输出:2
示例 3:
输入:a = “a”, b = “a”
输出:1
示例 4:
输入:a = “abc”, b = “wxyz”
输出:-1
提示:
1 <= a.length <= 104
1 <= b.length <= 104
a 和 b 由小写英文字母组成
class Solution {
/**
字符串匹配首先想到kmp算法,但我们需要先保证能匹配成功的条件:
1.b中不存在a中没有的字母
2.a的长度要大于等于b(还得处理刚好相等时,再加一次复制的情况)
*/
int[] ne = new int[10010];
public int repeatedStringMatch(String a, String b) {
int n = a.length(), m = b.length();
int[] cnt1 = new int[26], cnt2 = new int[26];
for (int i = 0; i < n; ++i) cnt1[a.charAt(i)-'a']++;
for (int i = 0; i < m; ++i) cnt2[b.charAt(i)-'a']++;
//如果b中存在a中没有的字母就肯定不能匹配成功
for (int i = 0; i < 26; ++i)
if (cnt1[i] == 0 && cnt2[i] != 0) return -1;
int count = 1; //初始肯定得复制1次
String s = a;
int k = n;
while (n < m) { //当s长度小于b长度就一直复制
s = s + a; //复制s
n += k;
count++;
}
boolean isTrue = matching(s,b);
if (isTrue) return count;
/**
为什么还要匹配一次?因为存在
"abcd"
"cdabcdab"这种样例 得再复制尝试一次
*/
count++;
s = s + a;
if (matching(s,b)) return count;
return -1;
}
//kmp算法
public boolean matching(String s1, String s2) {
int n = s1.length(), m = s2.length();
s1 = " " + s1;
s2 = " " + s2;
//求next
for (int i = 2, j = 0; i <= m; ++i) {
while (j > 0 && s2.charAt(i) != s2.charAt(j+1)) j = ne[j];
if (s2.charAt(i) == s2.charAt(j+1)) j++;
ne[i] = j;
}
//匹配过程
for (int i = 1, j = 0; i <= n; ++i) {
while (j > 0 && s1.charAt(i) != s2.charAt(j+1)) j = ne[j];
if (s1.charAt(i) == s2.charAt(j+1)) j++;
if (j == m) return true;
}
return false;
}
}