题目
给定两个字符串 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 由小写英文字母组成
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/repeated-string-match
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的题解
class Solution {
public int repeatedStringMatch(String a, String b) {
if(a.equals(b) || a.indexOf(b)>=0){
return 1;
}else if("".equals(b)){
return 0;
}else if((b.length()<a.length() && a.indexOf(b)<0 && (a+a).indexOf(b)<0)){
return -1;
}else{
for(char c : b.toCharArray()){
if(a.indexOf(c+"")<0){
return -1;
}
}
}
int count = 2;
StringBuilder sb = new StringBuilder(a+a);
while(sb.toString().indexOf(b)<0){
if(sb.toString().length()>(b.length()+a.length())) return -1;
count++;
sb.append(a);
}
return count;
}
}
说明
前面是基本校验:
- a与b相同或者a已经包含b,则直接返回 1
- b为空字符串返回 0
- b的长度小于a的长度,那么如果a不包含b并且a重复一次后也不包含b,则返回不存在 -1
- b中存在a不包含的字符,则返回不存在 -1
校验后直接从重复叠加a字符串2次开始进行迭代,每叠加一次进行判断叠加后的字符串是否包含b,如果包含则停止迭代;如果迭代过程中叠加字符串长度已经大于b字符串的长度加上a字符串的长度时( 当 b = a/n + a + … + a + a/n时, a叠加到长度大于等于b时,至少有一边是完全匹配,所以叠加字符串长度需要大于b+a的长度才能确定不包含),说明叠加字符串不包含b字符串,返回 -1。
执行用时:19 ms, 在所有 Java 提交中击败了 73.01% 的用户
内存消耗:39.1 MB, 在所有 Java 提交中击败了 5.54% 的用户
可以解决问题,效率一般。
官方题解
方法一:Rabin-Karp 算法
class Solution {
static final int kMod1 = 1000000007;
static final int kMod2 = 1337;
public int repeatedStringMatch(String a, String b) {
int an = a.length(), bn = b.length();
int index = strStr(a, b);
if (index == -1) {
return -1;
}
if (an - index >= bn) {
return 1;
}
return (bn + index - an - 1) / an + 2;
}
public int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
if (m == 0) {
return 0;
}
int k1 = 1000000009;
int k2 = 1337;
Random random = new Random();
int kMod1 = random.nextInt(k1) + k1;
int kMod2 = random.nextInt(k2) + k2;
long hashNeedle = 0;
for (int i = 0; i < m; i++) {
char c = needle.charAt(i);
hashNeedle = (hashNeedle * kMod2 + c) % kMod1;
}
long hashHaystack = 0, extra = 1;
for (int i = 0; i < m - 1; i++) {
hashHaystack = (hashHaystack * kMod2 + haystack.charAt(i % n)) % kMod1;
extra = (extra * kMod2) % kMod1;
}
for (int i = m - 1; (i - m + 1) < n; i++) {
hashHaystack = (hashHaystack * kMod2 + haystack.charAt(i % n)) % kMod1;
if (hashHaystack == hashNeedle) {
return i - m + 1;
}
hashHaystack = (hashHaystack - extra * haystack.charAt((i - m + 1) % n)) % kMod1;
hashHaystack = (hashHaystack + kMod1) % kMod1;
}
return -1;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/repeated-string-match/solution/zhong-fu-die-jia-zi-fu-chuan-pi-pei-by-l-vnye/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析
时间复杂度:O(n + m), 其中 n 为 a 的长度,m 为 b 的长度。Rabin-Karp 算法的时间复杂度为 O(n + m)。
空间复杂度:O(1)。只需要常数空间保存参数。
执行用时:3 ms, 在所有 Java 提交中击败了 96.14% 的用户
内存消耗:36.8 MB, 在所有 Java 提交中击败了 91.57% 的用户
这个算法效率最高
方法二:Knuth-Morris-Pratt 算法
class Solution {
public int repeatedStringMatch(String a, String b) {
int an = a.length(), bn = b.length();
int index = strStr(a, b);
if (index == -1) {
return -1;
}
if (an - index >= bn) {
return 1;
}
return (bn + index - an - 1) / an + 2;
}
public int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
if (m == 0) {
return 0;
}
int[] pi = new int[m];
for (int i = 1, j = 0; i < m; i++) {
while (j > 0 && needle.charAt(i) != needle.charAt(j)) {
j = pi[j - 1];
}
if (needle.charAt(i) == needle.charAt(j)) {
j++;
}
pi[i] = j;
}
for (int i = 0, j = 0; i - j < n; i++) { // b 开始匹配的位置是否超过第一个叠加的 a
while (j > 0 && haystack.charAt(i % n) != needle.charAt(j)) { // haystack 是循环叠加的字符串,所以取 i % n
j = pi[j - 1];
}
if (haystack.charAt(i % n) == needle.charAt(j)) {
j++;
}
if (j == m) {
return i - m + 1;
}
}
return -1;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/repeated-string-match/solution/zhong-fu-die-jia-zi-fu-chuan-pi-pei-by-l-vnye/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析
时间复杂度:O(n + m),其中 n 为 a 的长度,m 为 b 的长度。Knuth-Morris-Pratt 算法的时间复杂度为 O(n + m)。
空间复杂度:O(m)。Knuth-Morris-Pratt 算法需要 O(m) 的空间来保存 π 数组。