题目描述
给定两个字符串A
和B
,寻找重复叠加字符A
的最小次数,使得字符串B
成为叠加后的字符串A
的子串,如果不存在则返回-1
.
示例:
输入: A = “abcd”, B = “cdabcdab”
输出: 3
解释: A重复叠加三遍后为"abcdabcdabcd",此时B是其子串; A 重复叠加两边后为“abcdabcd”,B并不是其子串。
注意: A
与B
字符串的长度在1
和10000
区间范围内。
思路分析
题目难度为简单 ,这里简化题目意思就是输入字符串存在子母串关系前提下,如何判断A
的最小重复次数,如图1,图2 所示,这里我们可以将情况分为两种:
B
占据kA
的中间部分;B
至少占据kA
一端(开头或结尾)字符;
图1 情况1示意图
图2 情况2示意图
这里,我们进一步分析可知,若B
为A
的子串,则会在叠加A
后的子串长度小于等于2倍的B
字符串长度内检测到,故这里直接给出代码核心部分:
代码片1
StringBuiler strs = new StringBuilder(a);
int res = 1;
while(strs.length() < b.length()*3){ // or <= b.length() * 2
if(strs.indexOf(b) >= 0)
return res;
else{
strs.append(a);
res++;
}
}
情况完善
在上面的思考过程中,我们会发现仅适用于a.length() <= b.length()
的情况,如果a.length() > b.length()
,我们需要判断当strs.length() < a.length()*3
的情况(这里不做详细说明,可自行绘图):
- 若
B
为A
的中间子串,则在首次while
循环(仅叠加了一次)时,返回1
; - 若
B
占据A
的至少一端,则至多在第二次while
循环(叠加了两次)时,则会发现;
即当A.length() > B.length()
时,不存在当B
确实为A
,但两次叠加A
后无法检测的情况,故这里while
循环设置为while(strs.length() < a.length()*3)
。这时核心代码变成:
代码片2
while(strs.length() < a.length()*3){ // or <= a.length() * 2
if(strs.indexOf(b) >= 0)
return res;
else{
strs.append(a);
res++;
}
}
情况合并
此时,我们比较代码片1与代码片2,试图将其进行规整,我们发现while
循环条件均为strs.length() < x * 3
,这里的x
为输入字符串a,b
的最长者,则我们可以设置一基准长度baseLen
,将while
循环条件变量化:
int baseLen = Math.max(a.length(), b.length());
while (strs.length() < baseLen * 3) {
if (strs.indexOf(b) >= 0) {
return res;
} else {
strs.append(a);
res++;
}
}
进一步节省空间,我们直接将变量baseLen
省略,则有最终的解题代码:
解题代码
public static int solution(String a, String b) {
int res = 1;
StringBuilder strs = new StringBuilder(a);
while (strs.length() < 3 * Math.max(a.length(), b.length())) {
if (strs.indexOf(b) >= 0) {
return res;
} else {
strs.append(a);
res++;
}
}
return -1;
}
复杂度分析
我们设n,m
为A,B
的字符串长度
时间复杂度: 检测B
是否为子串时,其时间复杂度为O(m)
;strs
的长度最长为2max(n, m)
,故时间复杂度为O(m*max(n, m))
;
空间复杂度: 我们借助了StringBuiler strs
的辅助,且最长为2max(n, m)
,故空间复杂度为O(max(n, m))
;
Github源码
完整可运行文件请访问GitHub。