題目描述
給定兩個字符串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。