首先,要明白,如果b串的第一个字母b[0]在a串中没有找到,那么不管a串复制多少次,b串都不会是a的子串。
如果b串的第一个字母b[0]在a串中能找到,那么我们看一下a串需要复制几次呢?
总结,可以发现这四种情况是可以合并在一起写的,即a串最多复制b/2+2次,这也是一些题解为什么说a串最多复制b/2+2次。
第一种方法,用切片的方法判断b串是否是a串的子串
class Solution:
def repeatedStringMatch(self, a, b):
la=len(a)
lb=len(b)
flag=[]
for i in range(la):
if a[i]==b[0]:
#将a中b[0]出现的位置保存,因为
#比如a="aac" b="ac"
#不一定第一次匹配到的就恰好合适
flag.append(i)
else:
i+=1
if len(flag)==0:
return -1
else:
s=a
cnt=1
for i in flag:
while len(s)-i<lb:
s+=a
cnt+=1
if s[i:i+lb]==b:
return cnt
return -1
a=Solution()
print(a.repeatedStringMatch("abc", "cabcabca"))
第二种方法KMP算法
首先要知道KMP算法的思想
朴素模式匹配,就是暴力,从主串第一个位置看能否匹配,然后看第二个,如此进行下去
然后去看【天勤考研】KMP算法易懂版_哔哩哔哩_bilibili
再去看 KMP算法之求next数组代码讲解_哔哩哔哩_bilibili
构造好next数组就是匹配的过程了
代码如下
class Solution:
def repeatedStringMatch(self, a, b):
b=' '+b#加个空格,模式串整体右移
lb = len(b)
next=[0]*lb
next[1]=0#模式串1号位不匹配,把它置0
i,j=1,0
#i表示当前位上一位next数组的值
#j表示最长公共前缀的下一位
#构造next数组
while i<(lb-1):
#lb-1是因为,比如abc
#i=2时就把next[3]算出来了
if j==0 or b[i]==b[j]:
i+=1
j+=1
next[i]=j
else:
j=next[j]
'''
j=0,特判,1号位与主串的下一位比较
'''
#求模式串在主串第一次出现的位置
i,j=0,1
while i<len(a):
if j==0:#特判,j==0,是模式串的1号位与主串下一位比较
i+=1
j+=1
elif i< len(a) and a[i]==b[j]:#匹配成功
if j==(lb-1):
return i - j + 1
i += 1
j += 1
else:
j=next[j]
if i< len(a) and a[i]==b[j] and j==(lb-1):
return i-j+1
return -1
如果你发现next数组的初始值有好几种,那么到底哪个对呢?
可以看帮你把KMP算法学个通透!(求next数组代码篇)_哔哩哔哩_bilibili
解决你的疑惑
最后回归本题代码
class Solution:
def repeatedStringMatch(self, a, b):
flag=len(b)//len(a)+1
b=' '+b#加个空格,模式串整体右移
lb = len(b)
next=[0]*lb
next[1]=0#模式串1号位不匹配,把它置0
i,j=1,0
#i表示当前位上一位next数组的值
#j表示最长公共前缀的下一位
while i<(lb-1):
#lb-1是因为,比如abc
#i=2时就把next[3]算出来了
if j==0 or b[i]==b[j]:
i+=1
j+=1
next[i]=j
else:
j=next[j]
'''
j=0,特判,1号位与主串的下一位比较
'''
s = a
for i in range(flag):
s+=a
i, j = 0, 1
while i < len(s):
if j == 0:
i += 1
j += 1
elif i < len(s) and s[i] == b[j]: # 匹配成功
if j == (lb - 1):
return i//len(a)+1
i += 1
j += 1
else:
j = next[j]
if i < len(s) and s[i] == b[j] and j == (lb - 1):
return i//len(a)+1
return -1