解法
这个题目首先要转化成S1
里总共有多少个s2
,然后再整除n2
就是M
的值。
基于官方解答的思想但是不做法不太一样
中心思想是循环!就跟判断循环小数似的
我们需要找到一个对齐方式,然后判断某个模式是否循环。
比如说,对于官解例子里的s1="abaacdbac"
和s2="adcbd"
。
官解找的对齐模式是 遍历到s1
的第一个字母时,s2
的哪个下标之前的字母已经完成,于是我们有:
abaacdbac abaacdbac abaacdbac abaacdbac abaacdbac
a d c b d a d c b d a d
0 3 1 3 1
不难发现这个是重复的
具体请走官解
我这里找的对齐模式是:s2
的最后一个字母对应s1
的哪个下标,令s1="abab"
,s2="baab"
我们有:
abab abab abab abab abab
ba ab b a ab ba ab b
1 3 1
5 11 17
可以看出肯定是131313……
地循环了。
当我们在真实下标i
处对齐了s2
的最后一位,那么此时的对应下标为i%l1
。如果在前面已经出现过这个下标了,跟判断循环小数一样,循环节就前面的i%l1
处开始。
假设从前面在发现循环节之前已经对齐了a
个s2
,分别编号为0,...,a-1
,i%l1
所处的编号为b
,表示循环节从编号b
处开始。
编号为i
的对齐处的真实下标为idx[i]
那么循环节的真实长度为L=i-idx[b]
令L1=l1*n1
,对于剩下的L1-idx[b]
个字符,假设L1-idx[b]=xL+y
,其中x=(L1-idx[b])//L
,y = (L1-idx[b])%L
现在我们来判断S1
里有多少个s2
,首先,循环节前肯定有b
个,然后x
个循环节里肯定有a-b
个,难点在于剩下的y
个字符里有多少个。
不难发现,对于b<=k<a
,idx[k]-idx[b]
表示这个对齐处到循环节开始处的距离,如果idx[k]-idx[b]<=y
,那么剩下的y
个字符肯定能至少构成k-b+1
个s2
,所以我们要找到满足这个不等式的最大的k
。
最后s2
的数量为:k+1+x*(a-b)
几个需要注意的地方:
- 真实下标
i
不能超过S1
的长度L1
- 也有可能由于
n1
太小所以找不到循环节,甚至有可能s1
根本没法组成s2
,要注意处理
class Solution(object):
def getMaxRepetitions(self, s1, n1, s2, n2):
"""
:type s1: str
:type n1: int
:type s2: str
:type n2: int
:rtype: int
"""
from bisect import bisect_right
if n1==0:
return 0
l1,l2 = len(s1),len(s2)
idx = {}
f = []
i = j = 0
L1 = l1*n1
while i<L1:
while i<L1 and s1[i%l1]!=s2[j%l2]:
i += 1
if i<L1 and (j+1)%l2==0:
if i%l1 not in idx:
idx[i%l1] = len(f)
f.append(i)
else:
b = idx[i%l1]
a = len(idx)
rest = L1-f[b]
L = i-f[b]
k = bisect_right(f,rest%L+f[b]-1) if rest%L else b
# print a,b,rest,L
# print idx,f
ans = (rest//L)*(a-b)+k
return ans//n2
i += 1
j += 1
return len(f)//n2